Go:disable HTTP chunk mode

本文介绍了如何在 Go 服务端禁用 HTTP Chunked 编码。通过设置 `Content-Length` 头部,即使内容长度超过默认缓冲区大小(2048B),Go 也会计算准确的 Content-Length 并避免使用 Chunked 编码。此外,文章讨论了修改源码设置缓冲区大小的不推荐做法及其原因。

Go:disable HTTP chunk mode


1.结论

应用层显式设置 Content-Length,可以 disable chunk mode。

	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("Content-Length", "2049")
		writer.Write(bytes.Repeat([]byte("."), 2049))
	})

2.跑起来

Go demo:

package main

import (
	"bytes"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write(bytes.Repeat([]byte("."), 2049))
	})

	http.ListenAndServe(":9080", nil)
}

运行:

$ go run main.go 
^Csignal: interrupt

测试:

$ curl -v http://127.0.0.1:9080/
...
> 
< HTTP/1.1 200 OK
< Date: Wed, 28 Apr 2021 10:39:50 GMT
< Content-Type: text/plain; charset=utf-8
< Transfer-Encoding: chunked
< 
...(2049B)

即,当Go服务端写入2049B时,将使用chunk模式传输(Transfer-Encoding: chunked)。


3.查源码

Go版本:

$ go version
go version go1.13.6 linux/amd64

源码定义:

// net/http/server.go
// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 2048

// net/http/server.go
// Read next request from connection.
func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
	...
	w = &response{
		conn:          c,
		cancelCtx:     cancelCtx,
		req:           req,
		reqBody:       req.Body,
		handlerHeader: make(Header),
		contentLength: -1,
		...
	}
	...
	w.cw.res = w
	w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
	return w, nil
}

在创建http.response时指定buffer的大小:

// A response represents the server side of an HTTP response.
type response struct {
	...
	w  *bufio.Writer // buffers output in chunks to chunkWriter
	cw chunkWriter
	...
}

4.disable HTTP chunk mode

源码注释:【重点】

// If the handler didn't declare a Content-Length up front, we either
// go into chunking mode or, if the handler finishes running before
// the chunking buffer size, we compute a Content-Length and send that
// in the header instead.

如果你已经显式声明设置Content-Length,则不会进入chunk mode,否则,受到chunk buffer size限制:

1.超过chunk buffer size,use chunk mode;
2.未超chunk buffer size,Go底层计算Content-Length并填入HTTP应答Header;

因此,如果应用层已知HTTP应答总长度,直接设置Content-Length即可disable chunk:

package main

import (
	"bytes"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("Content-Length", "2049")
		writer.Write(bytes.Repeat([]byte("."), 2049))
	})

	http.ListenAndServe(":9080", nil)
}

此时,应用层写入2049B,超过chunk buffer size(2048),但是使用Content-Length而非chunk。

$ curl -v http://127.0.0.1:9080/
... 
< HTTP/1.1 200 OK
< Content-Length: 2049
< Date: Wed, 28 Apr 2021 11:00:00 GMT
< Content-Type: text/plain; charset=utf-8
< 
...(2049B)

5.不建议的方式

修改源码 src/net/http/server.go 中 bufferBeforeChunkingSize 值,例如:

// This should be >= 512 bytes for DetectContentType,
// but otherwise it's somewhat arbitrary.
const bufferBeforeChunkingSize = 1024(原2048

此时,应用层未设置Content-Length并写入1025B,重新编译运行,也将进入chunk mode:

func main() {
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write(bytes.Repeat([]byte("."), 1025))
	})

	http.ListenAndServe(":9080", nil)
}
$ go build main.go
$ ./main
$ curl -v http://127.0.0.1:9080/
...
> 
< HTTP/1.1 200 OK
< Date: Wed, 28 Apr 2021 11:12:53 GMT
< Content-Type: text/plain; charset=utf-8
< Transfer-Encoding: chunked
< 
...(1025B)

由于没有API设置 bufferBeforeChunkingSize 值,因此,只能通过源码方式修改。

这种方法不利于后续运维,因此不建议。

在 Python 函数中,若需要屏蔽 Pylint 的警告,可以通过特定的注释语法来实现。Pylint 是一种用于检查 Python 代码质量的工具,它能够识别代码风格问题、潜在错误以及不规范的写法。然而,在某些情况下,开发者可能希望临时忽略特定的警告,例如函数参数数量较多但设计合理的情况。 ### 屏蔽 Pylint 警告的方法 #### 1. **在函数定义前使用 `# pylint: disable-next=警告代码`** 如果希望屏蔽的是下一个代码行(通常是函数定义)的警告,可以在函数定义的上一行使用 `# pylint: disable-next=警告代码` 的形式。例如: ```python # pylint: disable-next=too-many-arguments def my_function(arg1, arg2, arg3, arg4, arg5): pass ``` 上述代码会忽略 `my_function` 函数因参数过多而触发的 `too-many-arguments` 警告[^1]。 #### 2. **在函数内部使用 `# pylint: disable=警告代码`** 如果需要屏蔽的是函数内部某一段代码的警告,可以在该段代码前添加 `# pylint: disable=警告代码`,这样 Pylint 会忽略从该行开始到函数结束的所有相关警告。例如: ```python def my_function(): # pylint: disable=unused-variable x = 10 y = 20 # y is not used ``` 上述代码会忽略 `y` 未被使用的警告。 #### 3. **在函数定义中使用 `# pylint: disable=警告代码`** 如果函数定义中包含多个警告需要屏蔽,可以直接在函数定义行后添加 `# pylint: disable=警告代码1,警告代码2,...`。例如: ```python def my_function(arg1, arg2, arg3, arg4, arg5): # pylint: disable=too-many-arguments,unused-variable x = 10 y = 20 # y is not used ``` 这种方式可以同时屏蔽多个警告。 #### 4. **使用 `# pylint: enable=警告代码` 恢复警告** 如果希望在函数中的某一段代码之后重新启用被屏蔽的警告,可以使用 `# pylint: enable=警告代码`。例如: ```python # pylint: disable=too-many-arguments def my_function(arg1, arg2, arg3, arg4, arg5): pass # pylint: enable=too-many-arguments ``` 这种方式可以确保警告在特定代码块之外重新生效。 ### 注意事项 - **避免滥用**:虽然可以通过注释屏蔽警告,但应尽量避免滥用,确保代码设计合理且符合 Pylint 的规范要求。 - **明确警告代码**:屏蔽警告时应明确指定具体的警告代码,而非使用通配符,以防止意外忽略其他重要警告。 - **注释位置**:注释应放置在正确的位置,以确保其作用范围符合预期。 ### 示例代码 ```python # pylint: disable-next=too-many-arguments def complex_function(a, b, c, d, e, f): print(f"Arguments: {a}, {b}, {c}, {d}, {e}, {f}") # pylint: disable=unused-variable def example_function(): temp = 5 # temp is not used print("Function executed") # pylint: enable=unused-variable ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值