使用 http.Request.Context() 而不是 context.Background() 时,文件不会提交到谷歌云存储

2024年 2月 9日 50.6k 0

使用 http.request.context() 而不是 context.background() 时,文件不会提交到谷歌云存储

php小编西瓜在介绍Go语言开发中的一个重要细节时指出,使用http.Request.Context()代替context.Background()时,上传文件不会被自动提交到谷歌云存储。这个小细节对于开发者来说非常重要,因为它可能会导致文件上传失败或数据丢失。了解并正确使用这个方法可以避免不必要的问题,确保文件的安全上传和存储。

问题内容

我是新手,我编写了一个简单的宠物项目来将加密文件上传到谷歌云存储。
问题:
在我调用 addentry 函数的http处理程序中,当我传递 r.context() 而不是 context.background() 时,文件不会上传到谷歌存储。在谷歌的控制台中,我可以看到收到的字节,而且我根本没有收到任何错误,但文件本身不存在。

处理程序代码:

//imports, structs skipped

func processaddentryrequest(w http.responsewriter, r *http.request) {
//validation, getting params from jwt skipped

reader, err := r.multipartreader()
if err != nil {
http.error(w, "multipart/form-data expected, not found", http.statusbadrequest)
log.println("could not init multipartreader from request: %w", err)
return
}

gsservice, err := googlestorageservice.new()
if err != nil {
http.error(w, "internal server error", http.statusinternalservererror)
log.println(err)
return
}

bservice, err := backupservice.new(
backupservice.withcipher(aes.new()),
backupservice.withstorageservice(gsservice))

if err != nil {
http.error(w, "internal server error", http.statusinternalservererror)
log.println(err)
return
}
var entry *entryrepo.backupentry
for {
part, err := reader.nextpart()
if err == io.eof {
break
}
if err != nil {
err = fmt.errorf("error reading: %w", err)
log.println(err)
http.error(w, "internal server error", http.statusinternalservererror)
return
}

formname := part.formname()
if formname == "file" {
entry, err = bservice.addentry(r.context(), backupid, part.filename(), part.header.get("content-type"), part)
if err != nil {
errclose := part.close()
err = fmt.errorf("failed to add entry for backup %s: %w; error while closing multipart.part: %w", backupid, err, errclose)
log.println(err)
http.error(w, "internal server error", http.statusinternalservererror)
return

}
}
err = part.close()
if err != nil {
err = fmt.errorf("failed to close part for backup %s: %w", backupid, err)
log.println(err)
http.error(w, "internal server error", http.statusinternalservererror)
return
}

}
response.entry = *entry
jsondata, err := json.marshal(response)
if err != nil {
http.error(w, "internal server error", http.statusinternalservererror)
log.println("failed to marshal json: %wn", err)
return
}
w.writeheader(http.statusok)
w.header().set("content-type", "application/json")
w.write(jsondata)
}

登录后复制

addentry函数代码:

func (backupservice *backupservice) addentry(ctx context.context, backupid string, entryfullname string,
entrymimetype string, in io.reader) (*ber.backupentry, error) {
// validation skipped for readability
entryid := uuid.new()
outpath := backupid + "/" + entryid.string()

entrychan := make(chan *ber.backupentry)
errchan := make(chan error)
go func() {
gstorageclient, err := backupservice.storageservice.getclient(ctx)
if err != nil {
errchan 登录后复制

我尝试过的:

  • 启用 godebug:http2debug=1 检查调试 http 日志。日志不同,我将它们放在下面。
  • 检查上下文是否在所有级别上都关闭:在http处理程序本身中,在addentry函数中添加encrypt函数。上下文没有关闭,一切似乎都工作正常。
  • r.context() 创建派生上下文,结果与 r.context() 相同
  • 显然,将 context.background() 而不是 r.context() 传递给 addentry 函数,就可以解决问题
  • r.context() 作为参数传递时的调试日志:

    ft-api | 2023/08/02 19:23:46 stdout: 2023/08/02 19:23:46 [2606f10843ab/yuha6i98ak-000004] "post http://0.0.0.0:8080/backup http/1.1" from 172.18.0.1:36052 - 200 570b in 193.850041ms
    ft-api | 2023/08/02 19:23:47 stdout: 2023/08/02 19:23:47 [2606f10843ab/yuha6i98ak-000005] "post http://0.0.0.0:8080/entry http/1.1" from 172.18.0.1:36052 - 200 127b in 171.975584ms
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header ":authority" = "oauth2.googleapis.com"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header ":method" = "post"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header ":path" = "/token"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header ":scheme" = "https"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header "content-type" = "application/x-www-form-urlencoded"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header "content-length" = "861"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header "accept-encoding" = "gzip"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9019: http2: transport encoding header "user-agent" = "go-http-client/2.0"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9968: http2: transport received headers flags=end_headers stream=3 len=42
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9968: http2: transport received data flags=padded stream=3 len=974 data="x1fx8bbx00x00x00x00x00x02xffx1dxd4Ɏxa3hx00x04xd0x7fxf1xb9ia&xeb܌]xb4xc9*lx01x05x06.x88%xd9xf7dxcdxd6xfcxfbxsf).qx88xf7xf7x12xa7)&$zx86x06xf7x97x7f.gfx94xdfxe9uf13dƸxe98=x9arxe33xe6fѶxa3xcfxd7Ϫn-x04x9b]x7fxafxfc|x95xec!hax97^[xa4xadx0fxe8xebx03:x051uxb1x12~2x1exf5xbexbftν9x8fxe7xedзxaaxacx87axa3xfd!x82ȡӝybxe3nxb8x91xf8x91*xa1xc5xe7x80xc1|ڗ}px99xd0dxf7xf8xc7xc7"xdax1dxablx96xa4x98xf1'xb2gxefxb1=x10ox7fx8dcx96x8dxc6xfexfcxaexdc?xb7fx0fxc0xa2kxb9^xd5!xc38xe2ax84xca1x83xfeg6xbanjpzwxcfxfbxd3jͯnx8dxacxf2[xbe۰xfcxxbfbpxbdxddx14xa1--xbe" (613 bytes omitted)
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9968: http2: transport received data flags=end_stream|padded stream=3 len=136 data=""
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 h2_bundle.go:9968: http2: transport received ping len=8 ping="x00x00x00x00x00x00x00x02"
    ft-api | 2023/08/02 19:23:47 stderr: 2023/08/02 19:23:47 transport.go:3015: http2: transport failed to get client conn for storage.googleapis.com:443: http2: no cached connection was available

    登录后复制

    context.background() 作为参数传递时的调试日志(我从日志中删除了 jwt 令牌值,但它在那里)

    ft-api | 2023/08/02 19:24:51 stdout: 2023/08/02 19:24:51 [2606f10843ab/ukd5p0sXox-000001] "POST http://0.0.0.0:8080/backup HTTP/1.1" from 172.18.0.1:38934 - 200 570B in 465.2635ms
    ft-api | 2023/08/02 19:24:52 stdout: 2023/08/02 19:24:52 [2606f10843ab/ukd5p0sXox-000002] "POST http://0.0.0.0:8080/entry HTTP/1.1" from 172.18.0.1:38934 - 200 127B in 172.084834ms
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport failed to get client conn for oauth2.googleapis.com:443: http2: no cached connection was available
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport creating client conn 0x40003cc780 to 142.250.186.74:443
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header ":authority" = "oauth2.googleapis.com"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header ":method" = "POST"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header ":path" = "/token"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header ":scheme" = "https"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header "content-type" = "application/x-www-form-urlencoded"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header "content-length" = "861"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header "accept-encoding" = "gzip"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9019: http2: Transport encoding header "user-agent" = "Go-http-client/2.0"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received SETTINGS len=18, settings: MAX_CONCURRENT_STREAMS=100, INITIAL_WINDOW_SIZE=1048576, MAX_HEADER_LIST_SIZE=65536
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received WINDOW_UPDATE len=4 (conn) incr=983041
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received SETTINGS flags=ACK len=0
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received HEADERS flags=END_HEADERS stream=1 len=220
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received DATA flags=PADDED stream=1 len=1030 data="x1fx8bbx00x00x00x00x00x02xffx1dxd4Irxa3:x00x00лxxddt1x83zx179&x86x84`#3n(!F3v̠xaex7fxf7x9fxea;xbczx7fOx98x90|x9ex93ehxf2xfexf4xe7t`x11xfc&xbfSxferxe7M'|x9dx83x1b'x06xdfx1fxa2xfaxcd]78xf5xc4,xedfx8fx18rxb9+xf8x1aņlxafx0f>"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "x-goog-api-client" = "gl-go/1.20.6 gccl/1.30.1"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "user-agent" = "gcloud-golang-storage/1.30.1"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "accept-encoding" = "gzip"
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received SETTINGS len=18, settings: MAX_CONCURRENT_STREAMS=100, INITIAL_WINDOW_SIZE=1048576, MAX_HEADER_LIST_SIZE=65536
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received WINDOW_UPDATE len=4 (conn) incr=983041
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received SETTINGS flags=ACK len=0
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received HEADERS flags=END_HEADERS stream=1 len=314
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received DATA stream=1 len=944 data="{"kind":"storage#object","id":"bucketname/a934c415-07bd-4686-8ad0-90ff5ef68c7e/6e6b9563-c9d9-484e-a24f-cd2f8bd1fcd8/1691004292747760","selfLink":"https://www.googleapis.com/storage/v1/b/bucketname/o/a934c415-07bd-4686-8ad0-90ff5ef68c7e%2F6e6b9563" (688 bytes omitted)
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received DATA flags=END_STREAM stream=1 len=0 data=""
    ft-api | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport received PING len=8 ping="x00x00x00x00x00x00x00x00"

    登录后复制

    解决方法

    通过在 gstorage 对象编写器上显式调用 Close() 方法而不是推迟它来解决该问题。我仍然不完全确定此行为的原因(我知道除非编写器关闭,否则文件不会提交到 gstorage,但不涉及上下文取消,因此它应该已关闭)。

    编辑:在我看来,问题可能出在 go 执行 goroutine 内部声明的延迟函数的顺序上。如果有人对此有解释,我们将非常欢迎。

    以上就是使用 http.Request.Context() 而不是 context.Background() 时,文件不会提交到谷歌云存储的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论