【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` ライブラリでは、以下のように記述する。

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

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

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

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

## クライアント
Golangのバージョンは、`go1.11.2 darwin/amd64`

```golang: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`

```javascript: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);
});
```

## 検証手順
サーバーのアプリケーションを起動する。

```bash
$ node server.js
```

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

```bash
$ go run main.go
```

### サーバーのログ

```bash
$ 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_face:

## リクエストヘッダーを組み立てる処理を以下のように修正
```golang:main.go
(略)
header := http.Header{}
header.Set("Content-Type", "application/json;charset=Shift_JIS")
(略)
```

### サーバーのログ
```bash
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