
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: %w
", 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 <- fmt.errorf("could not add entry: %w", err)
}
defer gstorageclient.close()
out := gstorageclient.bucket(config.gcbucketname()).object(outpath).newwriter(ctx)
defer out.close()
mac, size, err := backupservice.cipher.encrypt(ctx, in, out,
[]byte(config.encryptionkey()), []byte(config.hmackey()))
if err != nil {
errchan <- fmt.errorf("could not upload encrypted backupentry with id=%s: %w", entryid.string(), err)
}
//db operation skipped
entrychan <- entry
}()
select {
case <-ctx.done():
dbcleanuperr, storagecleanuperr := backupservice.cleanupentry(entryid.string(), outpath)
return nil,
fmt.errorf("could not add entry %s to backup %s: context was cancelled; db cleanup err: %w; gstorage cleanup err: %w",
entryid.string(), backupid, dbcleanuperr, storagecleanuperr)
case err := <-errchan:
dbcleanuperr, storagecleanuperr := backupservice.cleanupentry(entryid.string(), outpath)
return nil,
fmt.errorf("could not add entry %s to backup %s: %w; db cleanup err: %w; gstorage cleanup err: %w",
entryid.string(), backupid, err, dbcleanuperr, storagecleanuperr)
case entry := <-entrychan:
return entry, nil
}
}我尝试过的:
godebug:http2debug=1 检查调试 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=" Ɏh ia&܌]*l.%dxs).q)&$z.guf13dƸ8= 3fѶϪn-]|!ha^[:1u~2tν9з!ȡӝybn*|ڗ}pd"l'g=oc?fk^!81g6njpzwjͯn[۰xbp--" (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="