GO:HTTP应答头、状态码、应答体设置顺序

GO:HTTP应答头、状态码、应答体设置顺序

GO在HTTP回调处理函数中,对应答头、状态码、应答体的设置有顺序要求。

正确顺序:应答头(1)、状态码(2)、应答体(3)

正确示例:

package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"time"
)

func server() {
	go func() {
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			/* 设置应答头 */
			w.Header().Set("Content-Type", "application/json")

			/* 设置状态码 */
			w.WriteHeader(201)

			/* 设置应答体 */
			w.Write([]byte("{}"))
		})
		http.ListenAndServe(":1280", nil)
	}()
}

func client() {
	/* 发请求收应答 */
	ack, err := http.Get("http://127.0.0.1:1280/")
	if err != nil {
		panic(err)
	}
	defer ack.Body.Close()

	/* 导出应答 */
	ackDump, err := httputil.DumpResponse(ack, true)
	if err != nil {
		panic(err)
	}
	fmt.Printf("%s\n", ackDump)
}

func main() {
	// 服务端
	server()

	// 服务端异步,可能HTTP服务尚未创建好客户端已经开始连接而连接失败,需稍等
	time.Sleep(time.Second*5)

	// 客户端
	client()
}

运行:

[test1280@test1280 demo]$ go run main.go 
HTTP/1.1 201 Created
Content-Length: 2
Content-Type: application/json
Date: Fri, 13 Nov 2020 16:11:45 GMT

{}

此时,设置的状态码、应答头、应答体均成功生效。


错误示例1:先设置状态码,后设置应答头

func server() {
	go func() {
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			/* 设置状态码 */
			w.WriteHeader(201)

			/* 设置应答头 */
			w.Header().Set("Content-Type", "application/json")

			/* 设置应答体 */
			w.Write([]byte("{}"))
		})
		http.ListenAndServe(":1280", nil)
	}()
}

运行:

[test1280@test1280 demo]$ go run main.go 
HTTP/1.1 201 Created
Content-Length: 2
Content-Type: text/plain; charset=utf-8
Date: Fri, 13 Nov 2020 16:17:00 GMT

{}

可以看到,Content-Type是text/plain,而非application/json。

在调用w.WriteHeader后调用w.Header().Set是无效的。

net/http/server.go
Changing the header map after a call to WriteHeader (or Write) has no effect unless the modified headers are trailers.


错误示例2:先设置应答体,后设置状态码

func server() {
	go func() {
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			/* 设置应答头 */
			w.Header().Set("Content-Type", "application/json")

			/* 设置应答体 */
			w.Write([]byte("{}"))

			/* 设置状态码 */
			w.WriteHeader(201)
		})
		http.ListenAndServe(":1280", nil)
	}()
}

运行:

[test1280@test1280 demo]$ go run main.go 
2020/11/13 08:23:37 http: superfluous response.WriteHeader call from main.server.func1.1 (main.go:20)
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json
Date: Fri, 13 Nov 2020 16:23:37 GMT

{}

注意:

  • 错误输出:http: superfluous response.WriteHeader call from main.server.func1.1 (main.go:20)
  • 错误状态:期待201,实得200

在调用w.Write后调用w.WriteHeader是无效的。

net/http/server.go
If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) before writing the data.
If WriteHeader is not called explicitly, the first call to Write will trigger an implicit WriteHeader(http.StatusOK).

查阅源码:


net/http/server.go

// either dataB or dataS is non-zero.
func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
	……
	if !w.wroteHeader {
		w.WriteHeader(StatusOK)
	}
	……
}

可以看到:调用write时,判断如果没有调用过w.WriteHeader时,则设置200。


net/http/server.go

func (w *response) WriteHeader(code int) {
	……
	if w.wroteHeader {
		caller := relevantCaller()
		w.conn.server.logf("http: superfluous response.WriteHeader call from %s (%s:%d)", caller.Function, path.Base(caller.File), caller.Line)
		return
	}
	……
}

即,重复调用WriteHeader,只有第一次生效,其他时候无效返回。


总结:我们正确的设置顺序是:应答头(1) < 状态码(2) < 应答体(3)


参考:

1.https://golang.org/pkg/net/http/#Header.Set
2.https://www.cnblogs.com/liabio/p/11718439.html
3.https://stackoverflow.com/questions/42906490/whats-the-bad-effect-of-http-multiple-response-writeheader-calls

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值