首页>>后端>>Golang->Golang实践录:使用gin框架实现转发功能:上传文件并转发

Golang实践录:使用gin框架实现转发功能:上传文件并转发

时间:2023-12-01 本站 点击:0

近段时间需要实现一个转发 post 请求到指定后端服务的小工具,由于一直想学习 gin 框架,所以就使用这个框架进行尝试,预计会产生几篇文章。本文先研究如何在 gin 框架中实现上传和转发功能。

问题提出

一后台 web 服务,有众多历史版本,本身运行无问题,但后来需求变更,需将不同的历史版本单独运行,并指定不同端口。对外相当于有众多的服务。在请求 post 中带有日期时间,需要根据该日期时间将请求转发到不同的端口的后端服务。注意,post 请求是直接使用文件的形式,对文件名称有特定要求。

思路

nginx可以根据端口来转发,但本文是根据请求的内容转发的,因此需要实现一个转发工具。即先读取外部请求的文件内容,解析得到时间,再根据时间,转发到不同的端口服务中。要解决的问题: 如何做到既解析 post 请求,又要将该请求原封不动地发到后端服务?后端服务返回的数据,如何原封不动地返回请求者? 如何管理后端服务?如果使用额外的脚本,则添加了运维部署的步骤,略有麻烦。故考虑在转发工具中实现。

实现

使用工具进行 post 请求,并且指定文件名。可用 postman 或 curl,本文使用后者。

转发函数:

利用 ctx.Request.FormFile 得到文件名称、文件内容,此时,可以使用 gin 提供的 SaveUploadedFile 函数保存文件,也可以调用 io.Copy 保存。前者省事。

调用再次转发函数。

将再次转发函数返回值转换成 json 形式,返回 post 请求工具。

再次转发函数:

利用 multipart 包创建文件,将上一步得到的文件拷贝进去。

再用 http 库发送请求。注意需要设置格式。

最后读取请求的返回值,再返回,注意,内容为字节形式。

代码

主要接口代码

funcRunWebServer(args[]string){runWebOnlyPost()}funcrunWebOnlyPost(){router:=gin.New()router.Use(gin.Logger())router.Use(gin.Recovery())testRouter(router)klog.Println("Serverstartedat",conf.Port)router.Run(":"+conf.Port)}functestRouter(r*gin.Engine){fmt.Println("testpost...")r.POST("/foobar/test",foobar_test)r.POST("/foobar/test_back",foobar_test_back)}

实现代码

/*curlhttp://127.0.0.1:84/foobar/test-XPOST-F"file=@sample.json"临时:file读取了一次,再读就没有内容了,字节数为0*/funcfoobar_test(ctx*gin.Context){//2种方式都可,但ctx.Request.FormFile可以得到文件句柄,可直接拷贝//file,err:=ctx.FormFile("file")file,header,err:=ctx.Request.FormFile("file")iferr!=nil{ctx.JSON(http.StatusBadRequest,gin.H{"error":err,})return}//fmt.Printf("Request:%+v\n",ctx.Request);//fmt.Printf("Formfile:%+v|%+v|||%v%v\n",file,header,err,reflect.TypeOf(file));//拿到文件和长度,后面使用到varjsonfilenamestring=header.Filenamemysize:=header.Sizefmt.Printf("filename:%ssize:%d\n",jsonfilename,mysize);iferr!=nil{ctx.JSON(http.StatusBadRequest,gin.H{"error":err,})return}//处理json文件//注:如果读取了文件,再转发,就没有内容了,所以这里不读取//指向后端的服务URLurl:="http://127.0.0.1:85/foobar/test_back"resp:=post_data_gin(url,jsonfilename,file);//解析返回字符切片,得到map,当成json,赋值给ginvardata1map[string]interface{}err=json.Unmarshal(resp,&data1)//fmt.Println("mutiunmarshal:",err,data1)ctx.JSON(http.StatusOK,data1)return}/*模拟后台的仅获取file字段的json,不作其它处理curlhttp://127.0.0.1:84/foobar/test_back-XPOST-F"file=@sample.json"*/funcfoobar_test_back(ctx*gin.Context){//2种方式都可,但ctx.Request.FormFile可以得到文件句柄,可直接拷贝//file,err:=ctx.FormFile("file")_,header,err:=ctx.Request.FormFile("file")iferr!=nil{ctx.JSON(http.StatusBadRequest,gin.H{"code":-1,"msg":"failed","data":gin.H{"result":"failedinbackendserver",},},)return}//拿到文件和长度,后面使用到varmyfilestring=header.Filenamemysize:=header.Sizefmt.Printf("filename:%ssize:%d\n",myfile,mysize);ifmysize<=0{ctx.JSON(http.StatusBadRequest,gin.H{"code":-1,"msg":"failed","data":gin.H{"result":"failedinbackendserver,jsonsize0",},},)return}//此处可保存文件//保存成功返回正确的Json数据ctx.JSON(http.StatusOK,gin.H{"code":0,"msg":"ok","data":gin.H{"result":"okinbackendserver",},},)return}

为测试方便,文中实现的 gin 框架程序在运行时可指定端口。因此,代码中实现了2个 url 的响应函数。

测试

本文使用 sample.json 文件测试,内容如下:

{"enID":"ID250","exID":"ID251","exTime":"2020-10-17T20:00:27","type":1,"money":250.44,"distance":274050}

先运行 84 端口服务(称为 84 服务),此为对外的服务。再运行 85 端口服务(称为 85 服务),此为模拟后端的服务。 启动一终端,执行测试命令:

curlhttp://127.0.0.1:84/foobar/-XPOST-F"file=@sample.json"

84 服务打印:

[2021-11-1300:04:10.424busy.go:79]Serverstartedat84[GIN-debug]ListeningandservingHTTPon:84filename:sample.jsonsize:95iocopy:95<nil>[GIN]2021/11/13-00:05:33|200|3.0002ms|127.0.0.1|POST"/foobar/test"

85 服务打印:

[GIN-debug]ListeningandservingHTTPon:85filename:sample.jsonsize:95[GIN]2021/11/13-00:05:33|200|0s|127.0.0.1|POST"/foobar/test_back"

测试命令返回:

%Total%Received%XferdAverageSpeedTimeTimeTimeCurrentDloadUploadTotalSpentLeftSpeed1003611006310029831500145k--:--:----:--:----:--:--352k{"code":0,"data":{"result":"okinbackendserver"},"msg":"ok"}

也可直接向后端服务请求:

$curlhttp://127.0.0.1:85/fee/test_back-XPOST-F"file=@sample.json"%Total%Received%XferdAverageSpeedTimeTimeTimeCurrentDloadUploadTotalSpentLeftSpeed1003611006310029863000291k--:--:----:--:----:--:--352k{"code":0,"data":{"result":"okinbackendserver"},"msg":"ok"}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/5845.html