go net/http: WriteTimeout在写入完成之前超时 翻译结果:net/http中的WriteTimeout在写入完成之前发生超时,

djmepvbi  于 4个月前  发布在  Go
关注(0)|答案(7)|浏览(46)

你正在使用的Go版本是什么( go version )?

我检查了 go version go1.10 linux/amd64go 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
wixjitnu

wixjitnu1#

从Go 1开始,WriteTimeout可能需要一个更清晰的描述。也许只有我遇到这个问题,但不仅我需要多次阅读它,还需要检查源代码以确保我正确理解了它。
参考一下,现在它是这样的:

// WriteTimeout is the maximum duration before timing out
    // writes of the response. It is reset whenever a new
    // request's header is read. Like ReadTimeout, it does not
    // let Handlers make decisions on a per-request basis.
    WriteTimeout time.Duration
9wbgstp7

9wbgstp72#

我认为这段代码按照文档说明工作,尽管毫无疑问文档可以改进。如果你设置了一个短的超时时间,那么这个超时时间就会生效。我无法准确地告诉你想要的不同行为是什么;也许使用一个 context.Context 会在这里有所帮助。

6pp0gazn

6pp0gazn4#

我无法准确地告诉你你想要的不同行为。
WriteTimeout 的名称来看,人们可能会期望 timeout 适用于每个 Write 单独或写入响应整体。然而,实际上 WriteTimeout 对读取请求体、处理它(例如执行数据库查询)和写入响应施加了组合限制。
此外,即使在“请求处理”期间遇到 WriteTimeout,也不会在请求完全处理后(例如所有数据库查询都已执行)被检测到,直到尝试写入响应时才会被发现。与 context.Context 一样,WriteTimeout 有效地“中止”了长时间的请求,但与 context.Context 不同,它以相当低效的方式这样做,即它只阻止响应被写入。
因此,在我看来,有三个相关但独立的问题:

  • 由于请求花费太长时间的问题(如上所述),当前的行为值得怀疑。
  • 变量名有些误导性。
  • 文档有些模糊。

就文档而言,Mattermost 配置页面对 WriteTimeout 的实际作用有清晰而准确的描述:“这是从读取请求头结束到响应被写入的最大允许时间。”我喜欢它的措辞。

bhmjp9jg

bhmjp9jg5#

如果你对某个方面有建议,可以更新文档以澄清它,但正如其他人所说,我们不能在这里改变行为。
人们真正感兴趣的功能请求bug是 #16100 ,用于在Handler中操作超时。

wh6knrhe

wh6knrhe6#

这种令人困惑的行为是Mattermost中某些错误的根本原因:
https://mattermost.atlassian.net/browse/MM-9692mattermost/mattermost#8348

vuktfyat

vuktfyat7#

由于这个功能按预期工作并且有相应的文档记录,改变行为可能会破坏代码(由于Go 1兼容性承诺,我们无法这样做),这看起来是Go2需要考虑的事情。
我会让@bradfitz对此发表意见。

相关问题