Edited at

【Golang】net/httpを使ってリクエストヘッダーの属性に複数の値を付与する場合の注意点


概要

net/httpライブラリを使ってリクエストを送信する場合、Content-Typeに複数の値を格納してリクエストしたい。

なんてことがありますよね。

例えば、Content-Typeに


  • application/json

  • charset=Shift_JIS

を付与する場合、リクエストヘッダーは以下のように送信したいとします。

content-type=application/json;charset=Shift_JIS`

この;(セミコロン)で区切った形式で送信した場合、少しハマるポイントがあったので紹介します。


結論

content-type=application/json;charset=Shift_JIS

上記のように、;(セミコロン)で区切った値をリクエストヘッダーに付与して送信したい場合、

net/http ライブラリでは、以下のように記述する。


main.go

()

header := http.Header{}
header.Set("Content-Type", "application/json;charset=Shift_JIS")
()

以下のように記述した場合、想定した値にならない。


main.go

()

header := http.Header{}
header.Set("Content-Type", "application/json")
header.Add("Content-Type", "charset=Shift_JIS")
()


検証

クライアント、サーバーのアプリケーションを書いてサクッとリクエストヘッダーの中身を見てみた。


クライアント

Golangのバージョンは、go1.11.2 darwin/amd64


main.go

package main

import (
"bytes"
"fmt"
"net/http"

"github.com/labstack/echo"
)

func main() {

client := &http.Client{}

header := http.Header{}
header.Set("Content-Type", "application/json")
header.Add("Content-Type", "charset=Shift_JIS") // 今回問題の箇所

req, _ := http.NewRequest(
echo.POST,
"http://localhost:3000",
bytes.NewBufferString("hoge"),
)
req.Header = header

client.Do(req)
}



サーバー

nodeのバージョンは v9.11.2


server.js

var http = require('http');

var url = require('url');

var server = http.createServer(function (req, res) {
try {
console.log('requested.');
console.log('method: ' + req.method);
console.log('url: ' + req.url);
console.log('query: %j', url.parse(req.url, true).query);
console.log('user agent: ' + req.headers['user-agent']);
console.log('header' + JSON.stringify(req.headers));
}
catch (err) {
console.error('unhandled exception has occured.');
console.error(err);
}
finally {
res.end();
}
});
server.listen(3000, function () {
console.log('http server is running...press enter key to exit.');

process.stdin.on('data', function (data) {
if (data.indexOf('\n') !== -1) {
server.close(function () {
console.log('http server closed.');
process.exit(0);
});
}
});
});
server.on('error', function (err) {
console.error(err);
process.exit(1);
});



検証手順

サーバーのアプリケーションを起動する。

$ node server.js

クライアントアプリケーションを実行

$ go run main.go


サーバーのログ

$ node server.js

http server is running...press enter key to exit.
requested.
method: POST
url: /
query: {}
user agent: Go-http-client/1.1
header{"host":"localhost:3000","user-agent":"Go-http-client/1.1","content-length":"4","content-type":"application/json","accept-encoding":"gzip"}

headerのcontent-typeにcharset=Shift_JISがない...?:thinking:


リクエストヘッダーを組み立てる処理を以下のように修正


main.go

()

header := http.Header{}
header.Set("Content-Type", "application/json;charset=Shift_JIS")
()


サーバーのログ

http server is running...press enter key to exit.

requested.
method: POST
url: /
query: {}
user agent: Go-http-client/1.1
header{"host":"localhost:3000","user-agent":"Go-http-client/1.1","content-length":"4","content-type":"application/json;charset=Shift_JIS","accept-encoding":"gzip"}

期待通り。

net/httpライブラリの Header.Add は、 ;(セミコロン)区切りでContent-Typeを組み立てないことがわかった。


参照文献

https://golang.org/pkg/net/http/#Header.Add