cmd.exe / powershell.exe のcurlコマンドでPOSTした日本語データが文字化けする話と回避方法

こんにちは。神取です。
研修中にAzure Functionsの関数アプリの作成チュートリアルをしていた時の話です。

タイトルでcmd.exe / powershell.exeと書いていますが、
Windows TerminalからコマンドプロンプトやPowerShellを触っています。

よろしくお願いします。

事の発端

チュートリアルをここまでやった時、 GETに加えてPOSTも実験したいと考え、
コマンドプロンプト・PowerShellでcurl(Invoke-WebRequest)を使い実験したところ、
文字化けして以下のようになりました。

コマンドプロンプトの場合

C:\Users\Public\Documents\> curl -i -X POST -d "{\"name\":\"日本語\"}" http://localhost:7071/api/HttpExample
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 07:54:05 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

Hello, ���{��. This HTTP triggered function executed successfully..

PowerShellの場合

PS C:\> curl -Method POST -Body '{"name": "日本語"}' http://localhost:7071/api/HttpExample


StatusCode        : 200
StatusDescription : OK
Content           : Hello, ???. This HTTP triggered function executed successfully.
RawContent        : HTTP/1.1 200 OK
                    Transfer-Encoding: chunked
                    Content-Type: text/plain; charset=utf-8
                    Date: Wed, 26 May 2021 02:01:12 GMT
                    Server: Kestrel

                    Hello, ???. This HTTP triggered function executed successf...
Forms             : {}
Headers           : {[Transfer-Encoding, chunked], [Content-Type, text/plain; charset=utf-8], [Date, Wed, 26 May 2021 02:01:12 GMT],
                     [Server, Kestrel]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 63

はい。
日本語になっているはずの部分が、���{��???になってしまっています。

POSTされた側ではリクエストボディを読んで、nameの値を埋め込んで返しているだけなので、
POST時点で日本語文字がおかしくなっていそうです。

調べてみたところ、この問題の原因はcurlコマンド実行時の文字コードだと分かりました。
その回避策を以下に示します。

回避策

コマンドプロンプトの場合

コマンドプロンプトでは、-d オプションで渡すデータにUTF-8で保存したファイルを指定することで、
回避することが可能です。

  1. 送信用のデータをpost.jsonとして用意します。
{
    "name": "日本語"
}
  1. post.jsonをデータとしてcurlコマンドでPOSTします。
C:\Users\Public\Documents\> curl -i -X POST -d @post.json http://localhost:7071/api/HttpExample
HTTP/1.1 200 OK
Date: Wed, 26 May 2021 08:33:22 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

Hello, 日本語. This HTTP triggered function executed successfully.

���{��となっていた部分が正しく日本語と表示されるようになりました。

PowerShellの場合

PowerShellの場合は、-Body オプションで渡すデータをUTF-8でエンコードすることで回避できます。

PS C:\> curl -Method POST -Body ([System.Text.Encoding]::UTF8.GetBytes('{"name": "日本語"}')) http://localhost:7071/api/HttpExample


StatusCode        : 200
StatusDescription : OK
Content           : Hello, 日本語. This HTTP triggered function executed successfully.
RawContent        : HTTP/1.1 200 OK
                    Transfer-Encoding: chunked
                    Content-Type: text/plain; charset=utf-8
                    Date: Wed, 26 May 2021 08:36:47 GMT
                    Server: Kestrel

                    Hello, 日本語. This HTTP triggered function executed successf...
Forms             : {}
Headers           : {[Transfer-Encoding, chunked], [Content-Type, text/plain; charset=utf-8], [Date, Wed, 26 May 2021 08:36:47 GMT],
                     [Server, Kestrel]}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 69

???となっていた部分が正しく日本語と表示されるようになりました。

終わりに

素直にPostmanとか使えばこんな問題は起こらないんですけどね…
(ターミナル上で作業するので、別のコマンド操作とかに移りやすいのが利点ですかね?)

ちなみに、WSL(Ubuntuなど)からやる場合は文字化けは起こらないですが、
WindowsのlocalhostWSLのlocalhostは異なるので、ipconfigなどでホストのIPアドレスを調べて、
localhostと置き換える必要があります。

以上、
「cmd.exe / powershell.exe のcurlコマンドでPOSTした日本語データが文字化けする話と回避方法」
でした。

FIXER Inc. 神取 大貴
  • FIXER Inc. 神取 大貴
  • 21卒のつよつよになりたいFIXER社員です。
    tech blogも頑張っていきます。