2018年9月17日

小ネタ:PowershellでInvoke-RestMethodが文字化けする際の対処法

前置き


PowershellのInvoke-RestMethodコマンドレットでは、たまに日本語の文字化けが発生します。これはInboke-Restmethodが文字コードを誤って認識するために発生します。
戻り値の文字コードを指定する方法がないため、追加の対策にて文字コードを強制しましょう。
元ネタは以下です。
http://pierre3.hatenablog.com/entry/2014/12/13/001743

変換方法


まずはさらっとコードのご紹介です。

# NDLサーチからドラえもんの情報を拾う
$SearchData = 'title="ドラえもん" AND from="2017"'

$BaseUri = "http://iss.ndl.go.jp/api/sru?maximumRecords=10&operation=searchRetrieve&query="
Add-Type -AssemblyName System.Web
$OptionUri = [System.Web.HttpUtility]::UrlEncode($SearchData)

$uri = $BaseUri+ $OptionUri
# $xml = Invoke-RestMethod $uri
$res = Invoke-WebRequest $uri

$con =[System.Text.Encoding]::Utf8.GetString($res.RawContentStream.GetBuffer())
[xml]$xml = $con -replace "\u0000",""
$xml.searchRetrieveResponse.records.record[0].recordData
# REST APIの返却がJson形式の場合には以下を使用する。
$json = ConvertFrom-Json $con -replace "\u0000",""

まず、$resより前はリクエストのための情報なので、タイトルとは余り関係のない話ですが一応ご紹介です。
国会図書館サーチというサービスのSRUという検索APIを使用してタイトルに「ドラえもん」が含まれる蔵書(音楽CDなども含む)を検索し、結果をXMLで返しています。

このクエリー自体は実は化けないんですが、蔵書に海外の図書とかが含まれているからでしょうか、検索結果が化けたり化けなかったりするんです。
全部化ける前提のコードにすると化けなかった時に誤ったエンコード指定となってしまいます。

そこで、コマンドレットの自動変換に頼らず、一律でrawcontentからUTF8で読み込んでしまおうという訳です。
ただ、そうすると、パケットの詰め物なのかNUL(文字コード0000)が後方に埋まっているので文字列置換で取り除いてからXMLに変換しております。

補足


先日のElasticsearchの場合はElasticsearch側が仕様に反してましたが、今回はMS側が仕様に反している(一応)ので、そのうちこの回避策を使わなくてもPowershell側で対応してくれる可能性があります。

具体的には、JSONはRFC 8259にてエンコーディングにUTF-8を使用することを要件とされているため、Content-Typeの判定がJSONだった時点で、エンコーディングにISO-8859-1を利用してしまうのは仕様に反しております。
上の例はXMLなのでその制限はありません。ただ、これもコンテンツにencoding指定があるのでそれを元にUTF8で変換されるべきでしょうね。

0 件のコメント:

コメントを投稿

TIPS:VSCodeで日本語化がうまくいかないとき

前置き Visual Studio Codeで拡張機能「 Japanese Language Pack for Visual Studio Code 」を入れたら日本語になりますよね。 でも、「 Remote Development 」で色々な環境を日本語化してると、偶に...