你正在使用的Go版本是什么( go version
)?
我检查了 go version go1.10 linux/amd64
和 go version go1.9.4 linux/amd64
,它们的行为相同。
这个问题在最新版本中是否重现?
是的。
你正在使用什么操作系统和处理器架构( go env
)?
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/ubuntu/.cache/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/ubuntu/go"
GORACE=""
GOROOT="/usr/lib/go-1.10"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go-1.10/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build665138149=/tmp/go-build -gno-record-gcc-switches"
你做了什么?
我将 WriteTimeout
设置为一个比处理请求所需的时间更小的值。
https://gist.github.com/WGH-/90bbfe656e63f6fa457db84f91384c41
curl '18.196.145.219:8080/foo?t=1.5s' -v
你期望看到什么?
嗯,文档明确指出 "每当读取新请求的头部时,它都会被重置"。所以严格来说,一切都按预期工作。
然而,我期望 WriteTimeout
只会在耗时过长的写入调用中超时,或者至少它应该从第一次写入开始计时。这样更有意义。
你看到了什么?
一旦服务器尝试写入任何内容,即使之前从未写入过,假设已经超时,它将关闭连接。
curl: (52) Empty reply from server
7条答案
按热度按时间wixjitnu1#
从Go 1开始,WriteTimeout可能需要一个更清晰的描述。也许只有我遇到这个问题,但不仅我需要多次阅读它,还需要检查源代码以确保我正确理解了它。
参考一下,现在它是这样的:
9wbgstp72#
我认为这段代码按照文档说明工作,尽管毫无疑问文档可以改进。如果你设置了一个短的超时时间,那么这个超时时间就会生效。我无法准确地告诉你想要的不同行为是什么;也许使用一个
context.Context
会在这里有所帮助。jslywgbw3#
CC @bradfitz
6pp0gazn4#
我无法准确地告诉你你想要的不同行为。
从
WriteTimeout
的名称来看,人们可能会期望 timeout 适用于每个Write
单独或写入响应整体。然而,实际上WriteTimeout
对读取请求体、处理它(例如执行数据库查询)和写入响应施加了组合限制。此外,即使在“请求处理”期间遇到
WriteTimeout
,也不会在请求完全处理后(例如所有数据库查询都已执行)被检测到,直到尝试写入响应时才会被发现。与context.Context
一样,WriteTimeout
有效地“中止”了长时间的请求,但与context.Context
不同,它以相当低效的方式这样做,即它只阻止响应被写入。因此,在我看来,有三个相关但独立的问题:
就文档而言,Mattermost 配置页面对
WriteTimeout
的实际作用有清晰而准确的描述:“这是从读取请求头结束到响应被写入的最大允许时间。”我喜欢它的措辞。bhmjp9jg5#
如果你对某个方面有建议,可以更新文档以澄清它,但正如其他人所说,我们不能在这里改变行为。
人们真正感兴趣的功能请求bug是 #16100 ,用于在Handler中操作超时。
wh6knrhe6#
这种令人困惑的行为是Mattermost中某些错误的根本原因:
https://mattermost.atlassian.net/browse/MM-9692mattermost/mattermost#8348
vuktfyat7#
由于这个功能按预期工作并且有相应的文档记录,改变行为可能会破坏代码(由于Go 1兼容性承诺,我们无法这样做),这看起来是Go2需要考虑的事情。
我会让@bradfitz对此发表意见。