はじめに
前回はリクエストの*http.Request
に焦点を当てて、どのようにリクエストの中身を読み取るのかについてまとめました。
今回はhttp.ResponseWriter
とJSONに焦点を当ててまとめてみたいと思います。
ResponseWriter
サーバーを立てるときにはhttp.ResponseWriter
と*http.Request
を引数とした関数を用意します。
余談ですが、http.ResponseWriterはインターフェースなので一見値渡しのように見えますが、実際はresponseの参照渡しです。
ResponseWriterインターフェースには次の3つのメソッドがあります。
メソッド | 説明 |
---|---|
Write | レスポンスボディにデータを書き込みます。引数としてバイトスライスを受け取り、書き込んだバイト数とエラーを返します。 |
WriteHeader | レスポンスのステータスコードを設定します。通常、ステータスコードは最初の書き込みが行われる前に設定します。 |
Header | HTTPレスポンスヘッダを返します。レスポンスヘッダを設定するために使用します。 |
ResponseWriterへの書き込み
では、Write
メソッドを使用して以下のように書き込んでみます。
Write
は引数にバイトスライスを受け取り、それをHTTPレスポンスのボディに書き込みます。
package main
import (
"fmt"
"net/http"
)
func writeExample(w http.ResponseWriter, r *http.Request) {
// レスポンスボディにHTMLを書き込む
html := `<html>
<head><title>Example</title></head>
<body><h1>Hello, World!</h1></body>
</html>`
w.Write([]byte(html))
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/write", writeExample)
fmt.Println("Starting server at http://127.0.0.1:8080")
err := server.ListenAndServe()
if err != nil {
fmt.Println("Error starting server:", err)
}
}
リクエストを投げてみると、
%curl -i http://127.0.0.1:8080/write
以下のようにhtmlが返却されます。
HTTP/1.1 200 OK
Date: Tue, 09 Jul 2024 14:16:24 GMT
Content-Length: 86
Content-Type: text/html; charset=utf-8
<html>
<head><title>Example</title></head>
<body><h1>Hello, World!</h1></body>
</html>%
これまた余談ですが、なぜhtmlをバイトスライスに変換しているんだろうと気になり調べたところシリアライズというのがキーワードなのですね。お恥ずかしいですが、知りませんでした。。。
シリアライズすることで異なる環境やシステム間でデータを一貫して扱うことができるので、裏を返せばバイトスライスにしないと他の環境で読み込めない、となり得るということです。
io.WriteString
というものも用意されていて、こちらは引数に文字列を渡すことでレスポンスにデータを書き込めます。
WriteHeader
次にWriteHeader
ですが、これはHTTPレスポンスのステータスコードを設定するためのメソッドです。
何も指定しない場合はデフォルトで200 OK
をセットします。
また、WriteHeaderは呼び出された後にヘッダが変更されるのを防ぐので、コードの順番には注意が必要です。
例えば以下のようにWriteHeader(501)
とすることでステータスコードを501としてレスポンスを返すことができます。
...
func WriteHeaderExample(w http.ResponseWriter, r *http.Request){
w.WriteHeader(501)
fmt.Fprintln(w, "そのようなサービスはありません。")
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/writeheader", WriteHeaderExample)
err := server.ListenAndServe()
if err != nil {
fmt.Println("Error starting server:", err)
}
}
リクエストを投げると、
%curl -i http://127.0.0.1:8080/writeheader
次のようにステータスコードが501で返却されます。
HTTP/1.1 501 Not Implemented
Date: Tue, 09 Jul 2024 14:21:25 GMT
Content-Length: 49
Content-Type: text/plain; charset=utf-8
そのようなサービスはありません。
それにしても名前がややこしいです。。。WriteHeader
はヘッダーの設定っぽい名前ですが、ステータスコードをセットするメソッドです。
ヘッダーをセットするのはHeader
メソッドの方なので勘違いしないよう注意が必要ですね。
Header
最後にHeader
メソッドを見てみます。
Header
メソッドは、HTTPレスポンスのヘッダを操作するために使用されます。このメソッドは、レスポンスヘッダを設定するために必要なヘッダオブジェクトを返します。
定義を一部抜粋しましたが、Header
にはAdd
やSet
,Get
などのメソッドが用意されています。(個人的にはhas
が気になりました。)
func (h Header) Add(key, value string) {
textproto.MIMEHeader(h).Add(key, value)
}
func (h Header) Set(key, value string) {
textproto.MIMEHeader(h).Set(key, value)
}
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
...
今回はこの中のSet
を使用してヘッダーに追加してみたいと思います。ちなみにSet
はAdd
と違って既存の値がある場合は値を置き換えるので注意が必要です。追加したいならAdd
を使用しましょう。
先ほどのコードに追加します。
...
func HeaderExample(w http.ResponseWriter, r *http.Request){
w.Header().Set("Location", "http://google.com")
w.WriteHeader(302)
}
...
func main() {
...
http.HandleFunc("/redirect", HeaderExample)
...
これでリクエストを投げると、
%curl -i http://127.0.0.1:8080/redirect
Googleにリダイレクトされます。
HTTP/1.1 302 Found
Location: http://google.com
Date: Tue, 09 Jul 2024 14:34:58 GMT
Content-Length: 0
JSONの書き込み
最後にJSONの書き込み方についてです。
先ほどのコードに追加します。
まず、JSONはContent-Type
がapplication/json
なので、w.Header.Set(application/json)
でセットする必要があります。
そして、Post
構造体を用意し、使用します。これをjson.Marshal
でJSON形式のバイトスライスに変換して、w.Write()
で書き込みます。
...
type Post struct{
User string
Threads []string
}
...
func JsonExample(w http.ResponseWriter, r *http.Request){
w.Header().Set("Content-Type", "application/json")
post := &Post{
User: "TestUser",
Threads: []string{"1", "2", "3"},
}
json, _ := json.Marshal(post)
w.Write(json)
}
func main() {
...
http.HandleFunc("/json", JsonExample)
...
リクエストを投げると、
%curl -i http://127.0.0.1:8080/json
以下のようにJSONが返ってきます。
HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 09 Jul 2024 14:53:52 GMT
Content-Length: 43
{"User":"TestUser","Threads":["1","2","3"]}
まとめ
今回はhttp.ResponseWriter+JSONの書き込みについて以下の項目でまとめてみました。
- Write()
- WriteHeader()
- Header()
- json.Marshal
個人的にWriteHeader()の名前が分かりづらいから変えてほしい。。。