位置: IT常识 - 正文

gin框架中如何实现流式下载(gin框架使用案例)

编辑:rootadmin
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 团队中之前的文件下载做得比较复杂,因为担心量太大,是后台做异步的下载,最终生成文件,传送文件到CDN服务器,最后再告诉用户下载链接。 其实在查询接口中就可以实 ...

推荐整理分享gin框架中如何实现流式下载(gin框架使用案例),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:gin框架原理详解,gin框架原理详解,gin框架教程,gin框架context,gin框架中文文档,gin框架原理详解,gin框架中文文档,gin框架原理详解,内容如对您有帮助,希望把文章链接给更多的朋友!

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!

cnblogs博客zhihuGithub公众号:一本正经的瞎扯

团队中之前的文件下载做得比较复杂,因为担心量太大,是后台做异步的下载,最终生成文件,传送文件到CDN服务器,最后再告诉用户下载链接。其实在查询接口中就可以实现流式下载,这样查询接口和下载接口可以合二为一,更加简单。

gin框架中如何实现流式下载(gin框架使用案例)

下面是我的demo:

1.建立一个download_file的文件夹作为项目文件夹go mod init download_file2.生成go.mod文件,并准备对应的包:go get github.com/gin-gonic/gin@latestgo get github.com/gin-contrib/gzip

go.mod文件内容如下:

module download_filego 1.17require github.com/gin-gonic/gin v1.8.1require (github.com/gin-contrib/gzip v0.0.6 // indirectgithub.com/gin-contrib/sse v0.1.0 // indirectgithub.com/go-playground/locales v0.14.0 // indirectgithub.com/go-playground/universal-translator v0.18.0 // indirectgithub.com/go-playground/validator/v10 v10.10.0 // indirectgithub.com/goccy/go-json v0.9.7 // indirectgithub.com/json-iterator/go v1.1.12 // indirectgithub.com/leodido/go-urn v1.2.1 // indirectgithub.com/mattn/go-isatty v0.0.14 // indirectgithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirectgithub.com/modern-go/reflect2 v1.0.2 // indirectgithub.com/pelletier/go-toml/v2 v2.0.1 // indirectgithub.com/ugorji/go/codec v1.2.7 // indirectgolang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirectgolang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirectgolang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirectgolang.org/x/text v0.3.6 // indirectgoogle.golang.org/protobuf v1.28.0 // indirectgopkg.in/yaml.v2 v2.4.0 // indirect)3.main.go文件:3.1 初始化gin框架func main() {log.SetFlags(log.LstdFlags | log.Lshortfile)engine := gin.New()// engine.Use(gzip.Gzip(gzip.DefaultCompression)) //如果需要开启gzip压缩,取消这一行的注释engine.Handle("POST", "/query", downloadFile) // 假定查询和下载接口都是这条接口实现engine.Handle("GET", "/", homepage)engine.Run(":8080")}3.2 下载链接页,模拟post到新窗口的场景func homepage(ctx *gin.Context) {ctx.Header("Content-Type", "text/html")ctx.Writer.WriteString(`<html><body>open window and to download:<a href="javascript:download()">download</a><script>function download(){ var handle = window.open("about:blank", "my_download_window");document.forms[0].target = "my_download_window";document.forms[0].json.value="ahfu test";document.forms[0].submit();}</script><form action="/query" method="POST" enctype="multipart/form-data"><input type="hidden" name="json" value=""/></form></body></html>`)}

点击链接后,弹出新窗口,在新窗口中POST json数据

3.3 流式下载功能func downloadFile(ctx *gin.Context) {reqData, has := ctx.GetPostForm("json")if !has {ctx.Data(400, "text/plain","not found json form data")return} // 此处省略查询的业务逻辑 // todo: // 下面开始下载的准备ctx.Writer.WriteHeader(200)ctx.Header("Content-Type", "text/plain; charset=utf-8")ctx.Header("Transfer-Encoding", "chunked") // 告诉浏览器,分段的流式的输出数据// ctx.Header("Content-Encoding", "gzip") // 输出不是gzip内容,又加上这个头,浏览器会拒收。这里是个实验,不要加这行代码now := time.Now()fileName := now.Format("20060102_150405.csv")ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName)) // 设置下载的文件名ctx.Writer.WriteHeaderNow()// 下面模拟一个周期非常长的数据处理和下载过程for i := 0; i < 100; i++ {ctx.Writer.WriteString("\"")ctx.Writer.WriteString(str)ctx.Writer.WriteString("\"\t")ctx.Writer.WriteString("\"")ctx.Writer.WriteString(time.Now().Format("2006-01-02 15:04:05"))ctx.Writer.WriteString("\"\n")ctx.Writer.Flush() // 产生一定的数据后, flush到浏览器端time.Sleep(time.Duration(500) * time.Millisecond)}}

打开浏览器,输入:http://127.0.0.1:8080然后点击链接,过一会儿后会出现文件下载框。点击保存后,可以看见陆续下载文件的过程。注意:为什么过了一会儿才出现文件下载框?这是由于浏览器的缓冲机制导致的。如果一开始下载的字节数很多,就会很快出现下载框

3.4 启用gzip压缩

大流量的文本下载,可能很占带宽,我们可以开启GZIP压缩:

func main() {log.SetFlags(log.LstdFlags | log.Lshortfile)engine := gin.New()engine.Use(gzip.Gzip(gzip.DefaultCompression)) //如果需要开启gzip压缩,取消这一行的注释engine.Handle("POST", "/query", downloadFile) // 假定查询和下载接口都是这条接口实现engine.Handle("GET", "/", homepage)engine.Run(":8080")}

gin框架中已经提供gzip压缩的能力。

3.5 完整代码:// main.gopackage mainimport ("fmt""log""time""github.com/gin-contrib/gzip""github.com/gin-gonic/gin")func useGzip(engine *gin.Engine) {engine.Use(gzip.Gzip(gzip.DefaultCompression))}func main() {log.SetFlags(log.LstdFlags | log.Lshortfile)engine := gin.New()// engine.Use(gzip.Gzip(gzip.DefaultCompression)) //如果需要开启gzip压缩,取消这一行的注释engine.Handle("POST", "/query", downloadFile)engine.Handle("GET", "/", homepage)engine.Run(":8080")}func downloadFile(ctx *gin.Context) {reqData, has := ctx.GetPostForm("json")if !has {ctx.Data(400, "text/plain","not found json form data")return} // 此处省略查询的业务逻辑 // todo: // 下面开始下载的准备ctx.Writer.WriteHeader(200)ctx.Header("Content-Type", "text/plain; charset=utf-8")ctx.Header("Transfer-Encoding", "chunked") // 告诉浏览器,分段的流式的输出数据// ctx.Header("Content-Encoding", "gzip") // 输出不是gzip内容,又加上这个头,浏览器会拒收。这里是个实验,不要加这行代码now := time.Now()fileName := now.Format("20060102_150405.csv")ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName)) // 设置下载的文件名ctx.Writer.WriteHeaderNow()// 下面模拟一个周期非常长的数据处理和下载过程for i := 0; i < 100; i++ {ctx.Writer.WriteString("\"")ctx.Writer.WriteString(str)ctx.Writer.WriteString("\"\t")ctx.Writer.WriteString("\"")ctx.Writer.WriteString(time.Now().Format("2006-01-02 15:04:05"))ctx.Writer.WriteString("\"\n")ctx.Writer.Flush() // 产生一定的数据后, flush到浏览器端time.Sleep(time.Duration(500) * time.Millisecond)}}func homepage(ctx *gin.Context) {ctx.Header("Content-Type", "text/html")ctx.Writer.WriteString(`<html><body>open window and to download:<a href="javascript:download()">download</a><script>function download(){ var handle = window.open("about:blank", "my_download_window");document.forms[0].target = "my_download_window";document.forms[0].json.value="ahfu test";document.forms[0].submit();}</script><form action="/query" method="POST" enctype="multipart/form-data"><input type="hidden" name="json" value=""/></form></body></html>`)}

have fun. ?

本文链接地址:https://www.jiuchutong.com/zhishi/313079.html 转载请保留说明!

上一篇:Nginx 防盗链(nginx防盗链的作用)

下一篇:python多线程和多进程之间的联系(python多线程多核)

  • 湖南省居民健康卡怎么修改手机号(湖南省居民健康卡挂号后怎么查询)

    湖南省居民健康卡怎么修改手机号(湖南省居民健康卡挂号后怎么查询)

  • 微信如何开通抖音权限(微信如何开通抖音月付功能)

    微信如何开通抖音权限(微信如何开通抖音月付功能)

  • 小米充气宝能充汽车吗(小米充气宝能充suv小车吗)

    小米充气宝能充汽车吗(小米充气宝能充suv小车吗)

  • 苹果6s隔空投送在哪里(苹果6s隔空投送怎么用)

    苹果6s隔空投送在哪里(苹果6s隔空投送怎么用)

  • 商家如何查到匿名差评(商家可以看到匿名评价)

    商家如何查到匿名差评(商家可以看到匿名评价)

  • 推送引擎是什么意思(推送引擎是什么软件)

    推送引擎是什么意思(推送引擎是什么软件)

  • pr为什么导入不了视频(pr为什么导入不了mp3)

    pr为什么导入不了视频(pr为什么导入不了mp3)

  • 打印机已经加墨粉了,怎么还是用不了(打印机已经加墨粉了,怎么还是显示要加墨粉)

    打印机已经加墨粉了,怎么还是用不了(打印机已经加墨粉了,怎么还是显示要加墨粉)

  • 苹果手机cpu坏了能修吗(苹果手机cpu坏了里面的数据能恢复吗)

    苹果手机cpu坏了能修吗(苹果手机cpu坏了里面的数据能恢复吗)

  • 手机不能识别二维码是怎么回事(手机不能识别二位码)

    手机不能识别二维码是怎么回事(手机不能识别二位码)

  • iphone静音后闹钟还会响吗(iphone静音后闹钟还会震动吗)

    iphone静音后闹钟还会响吗(iphone静音后闹钟还会震动吗)

  • 小米note4上市时间(小米note4最新)

    小米note4上市时间(小米note4最新)

  • pe进不去是什么原因(pe进不去)

    pe进不去是什么原因(pe进不去)

  • 显示器dcr什么意思(显示器中的dcr是什么)

    显示器dcr什么意思(显示器中的dcr是什么)

  • QQ指定好友消息声音怎么取消(qq指定好友消息声音怎么取消)

    QQ指定好友消息声音怎么取消(qq指定好友消息声音怎么取消)

  • 无需合约版是国行吗(无需合约版是国行机吗)

    无需合约版是国行吗(无需合约版是国行机吗)

  • 苹果x电充满是什么显示(苹果x充满电显示出来是什么?)

    苹果x电充满是什么显示(苹果x充满电显示出来是什么?)

  • mate30国内什么时候发布

    mate30国内什么时候发布

  • 抖音被拉黑了还能艾特吗(抖音被拉黑了还能艾特对方看视频吗)

    抖音被拉黑了还能艾特吗(抖音被拉黑了还能艾特对方看视频吗)

  • 旺旺名是什么在哪里看(旺旺名叫什么大气一点)

    旺旺名是什么在哪里看(旺旺名叫什么大气一点)

  • 苏格兰高地上的厄克特城堡和内斯湖 (© AWL Images/Danita Delimont)(苏格兰高地什么意思)

    苏格兰高地上的厄克特城堡和内斯湖 (© AWL Images/Danita Delimont)(苏格兰高地什么意思)

  • Diffusion-GAN: Training GANs with Diffusion 解读

    Diffusion-GAN: Training GANs with Diffusion 解读

  • 微信小程序开发 app.json全局配置(微信小程序开发零基础入门)

    微信小程序开发 app.json全局配置(微信小程序开发零基础入门)

  • JS - 生成随机数的方法汇总(不同范围、类型的随机数)(js生成随机数字和字母组合)

    JS - 生成随机数的方法汇总(不同范围、类型的随机数)(js生成随机数字和字母组合)

  • 平价转让股权如何做
  • 应交税费科目的借贷方向
  • 固定资产清理费用为什么有进项税额
  • 建筑企业外地预缴
  • 什么情况下要交个人所得纳税
  • 个税手续费返还属于政府补助吗
  • 个人房租费收入怎么做账
  • 销售货物的运费增值税计入什么科目
  • 企业网银短信提醒费用
  • 物业公司收取的电费怎么确认收入
  • 新注册的公司什么时候可以开票纳税
  • 增值税发票抵扣联丢失怎么办
  • 消费税组成计税价格成本利润率
  • 用户风险是什么意思
  • 跨年租金收入会计分录
  • 纳税信用b
  • 公司减少注册资本的程序
  • 挂靠行为应当如何纳税?
  • 进项税额转出会计分录月末如何结转
  • 企业收到应收账款6要素哪个增加哪个减少
  • 不动产进项税为什么不能抵扣
  • 成本加成法的缺点
  • 公司决议效力确认纠纷
  • 税负率的销售收入是什么
  • 商品房买卖合同面积差3%法律规定
  • 期初银行余额有误怎么调分录怎么写
  • kb4499164安装失败怎么办
  • dll进程
  • 跨境服务免征增值税申报怎么填
  • php新手入门教程
  • 增值税普通发票和专用发票有什么区别
  • 购买用友财务软件
  • 财务费用核算的内容没有
  • 鹤望兰的养殖方法和注意事项浇水
  • php ladp
  • php批量上传
  • 投资公司收到境外债务
  • 收回以前年度款项如何处理
  • 搭建本地yum
  • 利息支出会计科目
  • 写出php的常用四种基本变量类型
  • sqlserver2008误操作数据
  • sql server 2008保存数据库
  • 银行每月贷款额度有多少
  • 收回以前年度的应收账款较多能说明什么呢?
  • 净资产利润率的公式是什么
  • 税金附加科目有哪些
  • 建设期收到罚单怎么处罚
  • 收到税务局汇算清缴退所得税怎么做账
  • 如何计提五险一金比例
  • 如何对企业进行有效的控制
  • sql存储过程什么意思
  • ubuntu安装软件没反应
  • xp系统如何开启共享文件夹
  • windows没网络是怎么回事
  • win10找不到打印机驱动
  • 微软宣布将AI引入Office套件
  • xp系统ie浏览器怎么升级
  • bootcamp您的磁盘未能分区
  • windows1020h2更新失败
  • 双系统其中一个系统无法开机
  • android native opengl
  • node做爬虫
  • Highcharts+NodeJS搭建数据可视化平台示例
  • linux4个主要部分
  • 文章标题作用答题模板
  • 定时软件有哪些
  • vue实现下载功能
  • python生成随机数据
  • python 描述符类
  • [置顶] 快来貌相则不达很好skmzx5
  • Python for Informatics 第11章之正则表达式(四)
  • js自定义指令
  • 事件的分发与传播的关系
  • 贴现再贴现转贴现的联系
  • 组织收入原则三个务必
  • 仓储物流企业的双控是指什么
  • 江苏企业所得税税率2023
  • 新旧鞋号码对比图
  • 融资租赁 合同
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设