位置: 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多线程多核)

  • iphonexr怎么录屏幕视频(iphonexr怎么录制屏幕)

    iphonexr怎么录屏幕视频(iphonexr怎么录制屏幕)

  • 云端照片怎么恢复到相册(云端照片怎么恢复到相册苹果手机)

    云端照片怎么恢复到相册(云端照片怎么恢复到相册苹果手机)

  • 苹果13寸笔记本多大长宽(苹果13寸笔记本有a4纸大吗)

    苹果13寸笔记本多大长宽(苹果13寸笔记本有a4纸大吗)

  • 腾讯视频昵称审核要多久(腾讯视频的昵称)

    腾讯视频昵称审核要多久(腾讯视频的昵称)

  • 魅族16生产日期(魅族16th出厂日期查询)

    魅族16生产日期(魅族16th出厂日期查询)

  • 华为荣耀20pro手机相册拼图怎么拼(华为荣耀20pro手机怎么开空调)

    华为荣耀20pro手机相册拼图怎么拼(华为荣耀20pro手机怎么开空调)

  • 小米CC9怎样删除相册里的照片和视频(小米cc9怎样删除应用)

    小米CC9怎样删除相册里的照片和视频(小米cc9怎样删除应用)

  • 微信为什么发不了长视频(微信为什么发不了语音)

    微信为什么发不了长视频(微信为什么发不了语音)

  • 7p可以遥控空调嘛(7p能控制空调吗)

    7p可以遥控空调嘛(7p能控制空调吗)

  • Word目录的行距怎么调(word目录的行距怎么改)

    Word目录的行距怎么调(word目录的行距怎么改)

  • 朋友圈设置了部分朋友不可见,别人知道吗(发的朋友圈设置了)

    朋友圈设置了部分朋友不可见,别人知道吗(发的朋友圈设置了)

  • 苹果手机照片有个感叹号怎么恢复(苹果手机照片有回收站吗)

    苹果手机照片有个感叹号怎么恢复(苹果手机照片有回收站吗)

  • 淘宝自动确认收货后还能退货吗(淘宝自动确认收货后运费险还有效吗)

    淘宝自动确认收货后还能退货吗(淘宝自动确认收货后运费险还有效吗)

  • 网盘会员到期文件会消失吗(网盘会员到期文件能打开吗)

    网盘会员到期文件会消失吗(网盘会员到期文件能打开吗)

  • 华为p30pro可以升5g嘛(华为p30pro可以升级5g手机吗)

    华为p30pro可以升5g嘛(华为p30pro可以升级5g手机吗)

  • ps建组的快捷键(ps如何快速建组)

    ps建组的快捷键(ps如何快速建组)

  • 怎么查自己名下的手机号(怎么查自己名下有没有房产)

    怎么查自己名下的手机号(怎么查自己名下有没有房产)

  • 如何用手机设置备忘录(如何用手机设置路由器密码)

    如何用手机设置备忘录(如何用手机设置路由器密码)

  • 怎么设置微信顶置文案(怎么设置微信顶上的文字)

    怎么设置微信顶置文案(怎么设置微信顶上的文字)

  • OPPO k5怎么通话录音(oppok5怎么设置电话录音)

    OPPO k5怎么通话录音(oppok5怎么设置电话录音)

  • vivo手机云相册在哪里打开(vivo手机云相册在哪里找到)

    vivo手机云相册在哪里打开(vivo手机云相册在哪里找到)

  • 6S摄像头下发热的原因(6s摄像头发热是怎么回事)

    6S摄像头下发热的原因(6s摄像头发热是怎么回事)

  • 华为a03l是什么型号(华为a乚00是什么型号)

    华为a03l是什么型号(华为a乚00是什么型号)

  • 一闪怎么保存到本地(一闪怎么保存到桌面上)

    一闪怎么保存到本地(一闪怎么保存到桌面上)

  • qq企业用户是什么(qq企业用户是啥)

    qq企业用户是什么(qq企业用户是啥)

  • QQ音乐Qplay功能如何使用(qq音乐 qplay)

    QQ音乐Qplay功能如何使用(qq音乐 qplay)

  • p30手电筒快捷键(华为p30手电筒快捷键)

    p30手电筒快捷键(华为p30手电筒快捷键)

  • 如何修改信用卡预留手机号(如何修改信用卡邮寄地址)

    如何修改信用卡预留手机号(如何修改信用卡邮寄地址)

  • 已抵扣的进项税发票怎么查询明细
  • 税点是什么费用
  • 外贸企业指的是什么
  • 旅游业小规模纳税人的认定标准是什么
  • 台港澳与境内合资企业和央企哪个好
  • 2019印花税减免
  • 税前利润总额的计算公式
  • 工程前期土地平整的会计分录怎么写?
  • 应收账款因质量不符合退货应该实施什么审计程序
  • 库存现金限额一般由开户银行根据企业
  • 用于文化活动费用的科目
  • 增值税发票红字发票怎么做凭证
  • 异地承包工程预缴什么税?
  • 结转增值税的计算公式
  • 怎么查找使用手机的时间
  • 一般纳税人花椒税率
  • 商家拒开发票的五大借口
  • 增值税和增值税额的区别
  • 每月收到融资租赁费利息发票
  • 二手车没购车发票有影响吗
  • 外挂项目跨年结转分录怎么做?
  • 无形资产怎么计算摊销
  • 服务费主营业务收入会计分录
  • 垃圾处理站利润
  • 支付销售佣金如何做账
  • 金蝶k3外购入库单套打设置
  • 表格关闭函数
  • 明股实债和明债实股
  • 预付款指的是
  • Vue3+ElementPlus el-date-picker设置可选时间范围
  • 新会计制度出台的背景
  • 现金清查的会计科目
  • 固定资产折旧的方法有几种
  • 接受投资收到的现金计入
  • 生产车间生产人员福利费
  • 以前年度亏损现在不亏了
  • push添加对象
  • 季报弥补亏损,财报怎么填
  • 电子税务局已申报的财务报表怎么修改
  • 弃置费用的现值计入固定资产
  • 发票第一联需要盖发票专用章吗
  • 如何在税控盘上申领发票
  • 发票认证后总局没信息
  • 开具免税的发票,"税率"栏如何填开?
  • 烟草专卖生产企业许可证
  • 工业企业的会计核算程序
  • 财务费用的内容包括哪些
  • 影响无形资产的营业利润怎么算
  • 什么叫同级财政收支
  • 上年亏损次年赢亏怎么算
  • 公交车经营权转让案例
  • 跨年租赁费会计分录
  • 电子设备折旧残值率
  • 办公报销项目
  • 加油票抬头开错了
  • 总资产报酬率的利息支出是财务费用吗
  • 实际利率与名义利率的换算
  • sql server高级编程
  • mysql加密解密
  • sqlserver 禁用触发器 超时
  • winxp怎么设置启动项
  • 电脑开机绿
  • win10系统运行速度慢
  • explorer.exe进程出错
  • linux安装sshpass
  • linux awk nr
  • linux常用命令查询
  • cocos2d-x 3.2 在window平台vs2012下解决中文乱码问题
  • 安卓笔记软件squid使用教程
  • linux保存
  • jquery的使用步骤
  • jquery.multiselect多选下拉框实现代码
  • javascrpt绑定事件之匿名函数无法解除绑定问题
  • JavaScipt中Function()函数的使用教程
  • python socket server
  • jquery中有哪些dom操作?
  • jqgrid分页pager
  • android解压app
  • 吉林省国税税务总局官网
  • 深圳布吉下水径旧改
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设