0

0

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

PHPz

PHPz

发布时间:2024-02-09 16:24:17

|

567人浏览过

|

来源于stackoverflow

转载

使用 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: %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
    }
}

我尝试过的:

ColorMagic
ColorMagic

AI调色板生成工具

下载
  1. 启用 godebug:http2debug=1 检查调试 http 日志。日志不同,我将它们放在下面。
  2. 检查上下文是否在所有级别上都关闭:在http处理程序本身中,在addentry函数中添加encrypt函数。上下文没有关闭,一切似乎都工作正常。
  3. r.context() 创建派生上下文,结果与 r.context() 相同
  4. 显然,将 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="Ɏhia&܌]*l.%dxs).q)&$z.guf13dƸ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=""
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="Ir:лxt1z9&`#3n(!F3̠;zO|eht`&S
M'|']78,fr+ņl<\#8Op#|}&ME-<ЕXy<HL5&{?yT:ȿX9K[4ԟa9 h0hk)5vT*4|P̍(l=dcqŖQ|w" (611 bytes omitted)
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received DATA flags=END_STREAM|PADDED stream=1 len=208 data=""
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 h2_bundle.go:9968: http2: Transport received PING len=8 ping=""
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport failed to get client conn for storage.googleapis.com:443: http2: no cached connection was available
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:3015: http2: Transport creating client conn 0x400029e000 to 216.58.212.144:443
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header ":authority" = "storage.googleapis.com"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header ":method" = "POST"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header ":path" = "/upload/storage/v1/b/bucketname/o?alt=json&name=a934c415-07bd-4686-8ad0-90ff5ef68c7e%2F6e6b9563-c9d9-484e-a24f-cd2f8bd1fcd8&prettyPrint=false&projection=full&uploadType=multipart"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header ":scheme" = "https"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "content-type" = "multipart/related; boundary=976d8006696028fea8c40fc53fe0a817a80f334ae41925d1e08c3bb3c917"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "x-cloud-trace-context" = "cb5a9d07f5007be3d8dfe277e1fb6beb/9294889295348469653;o=0"
ft-api  | 2023/08/02 19:24:52 stderr: 2023/08/02 19:24:52 transport.go:2076: http2: Transport encoding header "authorization" = "Bearer <<token value removed>>"
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=""

解决方法

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

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

相关文章

谷歌浏览器
谷歌浏览器

谷歌浏览器Google Chrome是一款可让您更快速、轻松且安全地使用网络的浏览器。Google Chrome的设计超级简洁,使用起来得心应手。这里提供了谷歌浏览器纯净安装包,有需要的小伙伴快来保存下载体验吧!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Go中Type关键字的用法
Go中Type关键字的用法

Go中Type关键字的用法有定义新的类型别名或者创建新的结构体类型。本专题为大家提供Go相关的文章、下载、课程内容,供大家免费下载体验。

238

2023.09.06

go怎么实现链表
go怎么实现链表

go通过定义一个节点结构体、定义一个链表结构体、定义一些方法来操作链表、实现一个方法来删除链表中的一个节点和实现一个方法来打印链表中的所有节点的方法实现链表。

462

2023.09.25

go语言编程软件有哪些
go语言编程软件有哪些

go语言编程软件有Go编译器、Go开发环境、Go包管理器、Go测试框架、Go文档生成器、Go代码质量工具和Go性能分析工具等。本专题为大家提供go语言相关的文章、下载、课程内容,供大家免费下载体验。

265

2023.10.13

0基础如何学go语言
0基础如何学go语言

0基础学习Go语言需要分阶段进行,从基础知识到实践项目,逐步深入。php中文网给大家带来了go语言相关的教程以及文章,欢迎大家前来学习。

720

2023.10.26

Go语言实现运算符重载有哪些方法
Go语言实现运算符重载有哪些方法

Go语言不支持运算符重载,但可以通过一些方法来模拟运算符重载的效果。使用函数重载来模拟运算符重载,可以为不同的类型定义不同的函数,以实现类似运算符重载的效果,通过函数重载,可以为不同的类型实现不同的操作。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

196

2024.02.23

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

241

2024.02.23

go语言开发工具大全
go语言开发工具大全

本专题整合了go语言开发工具大全,想了解更多相关详细内容,请阅读下面的文章。

304

2025.06.11

go语言引用传递
go语言引用传递

本专题整合了go语言引用传递机制,想了解更多相关内容,请阅读专题下面的文章。

175

2025.06.26

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Rust 教程
Rust 教程

共28课时 | 6.8万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

Go 教程
Go 教程

共32课时 | 6.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号