はじめに
個人開発をしている大学生やまいです。現在は読書家向けSNSを開発しており、本記事もそれの一環です。今後も本開発で学んだことを発信していくため、似たようなものを作りたいという方は追ってください。
この世にはcurl
とInvoke-RestMethod
でPOST
した際に日本語が文字化けするという問題があります。本記事ではその解決法を紹介します。
環境
- OS
- Windows11
- Go
- 1.23.2 windows/amd64
- PostgreSQL
- 1.5.11
- PowerShell
- 7.2.24
発生した問題
一番最初に実行していたコマンドはこちらです。これではPOST
したBookTitleとContentが???になってしまいます。
Invoke-RestMethod -Uri "http://localhost:8080/reviews" -Method Post -Headers @{"Content-Type"="application/json"} -Body (@{ BookTitle="吾輩は猫である"; Content="おもろかった"} | ConvertTo-Json -Depth 10 -Compress)
インサートした際の出力
ID BookTitle Content CreatedAt
-- --------- ------- ---------
8 ??????? ?????? 2025/03/06 13:52:32
今回のシステムではPowerShell
からリクエストを送信→Go
のプログラムがそれを取得しDB
に登録という形でインサートしています。
行った対策
1.SQLから直接INSERT
まずはどこで文字化けが起きているのか特定するためにPowerShell
から直接DB
にインサートします。
docker exec -it book_review_db psql -U user -d book_review -c "INSERT INTO reviews (BookTitle, Content) VALUES ('吾輩は猫である', 'おもろかった');"
すると、文字化けせずにインサートすることができました。
2.Go側で受け取ったJSONデータを確認
前節でPostgreSQL側の設定が正しく、PowerShell
からGo
にリクエストを送信している部分かGo
のプログラムがDB
に登録している部分のどちらかで文字化けが起こっていることが確認できました。
POST
メソッドを受け取るGo
のプログラムに受け取ったJSONデータを確認するプログラムを追加します。
package controllers
import (
"bytes"
"dokusyo/backend/database"
"dokusyo/backend/models"
"fmt"
"io"
"net/http"
"github.com/gin-gonic/gin"
)
// 感想一覧を取得
func GetReviews(c *gin.Context) {
var reviews []models.Review
database.DB.Find(&reviews)
c.JSON(http.StatusOK, reviews)
}
// 新しい感想を投稿
func CreateReview(c *gin.Context) {
var review models.Review
// クライアントから送信された JSON を確認
jsonData, _ := c.GetRawData()
fmt.Println("Received JSON:", string(jsonData))
// 読み取ったデータを元にリクエストのボディを再セット
c.Request.Body = io.NopCloser(bytes.NewBuffer(jsonData))
if err := c.ShouldBindJSON(&review); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Go 内部で受け取ったデータを確認
fmt.Println("Parsed Review:", review.BookTitle, review.Content)
database.DB.Create(&review)
c.JSON(http.StatusCreated, review)
}
このプログラムににより、Go
側のRecieved JSON:で????が表示、つまりPowerShell
から送信した時点でJSONのエンコーディングが壊れていることが分かった。
3.ConvertTo-Jsonを使用
コマンドにConvertTo-Json
オプションを追加し実行。
Invoke-RestMethod -Uri "http://localhost:8080/reviews" -Method Post -Headers @{"Content-Type"="application/json; charset=utf-8"} -Body ($(@{ BookTitle="吾輩は猫である"; Content="おもろかった"} | ConvertTo-Json -Depth 10 -Compress))
結果変わらず、エンコーディングは崩れたまま?????が保存された
4.UTF-8にエンコードして送信(解決)
最初にbody
部分を定義、その後エンコードして送信する。
$body = '{ "BookTitle": "吾輩は猫である", "Content": "おもろかった" }';
$utf8Body = [System.Text.Encoding]::UTF8.GetBytes($body);
Invoke-RestMethod -Uri "http://localhost:8080/reviews" -Method Post -Headers @{"Content-Type"="application/json; charset=utf-8"} -Body $utf8Body
これによってエンコーディングは崩れずインサートすることができた。
わかったこと
解決法として、先にUTF-8
にエンコードしてから送信すると文字崩れが起きないことが分かった。
MicrosoftのInvoke-RestMethod
ページを参照したところ、PowerShell7.4
以降ではUTF-8
に設定されていると書かれている。そこでPowerShell
のバージョンを確認してみると...
$PSVersionTable.PSVersion
Major Minor Patch PreReleaseLabel BuildLabel
----- ----- ----- --------------- ----------
7 2 24
コレガゲンインデスネスミマセン
なお、curl
コマンドを実行しても文字化けせずにインサートすることができる。
-X POSTを使うパターン
curl.exe --data '"{\"BookTitle\": \"吾輩は猫である\", \"Content\": \"おもろかった\"}"' --verbose --request POST --url "http://localhost:8080/reviews"
--jsonを使うパターン
curl --json '"{\"BookTitle\": \"吾輩は猫である\", \"Content\": \"おもろかった\"}"' http://localhost:8080/reviews
参考文献