百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

再也不怕获取不到Gin请求数据了

bigegpt 2024-09-22 00:42 3 浏览

以前阅读过Gin源码、并仿照Gin自己写了一个简单版的框架。

  1. Gin框架简洁版
  2. Gin源码剖析

最近在使用的时候,发现前端调用传递参数方式各异,各种稀奇古怪的方式都会用到。这篇文章主要盘一下如何获取到参数,方便今后使用。

代码位置:https://github.com/shidawuhen/asap/tree/master/controller/paramtype

1.类型

HTTP请求方法有很多

我们常用的是GET和POST,本次主要讲GET和POST,差不多可以覆盖所有的传递参数方式了。使用POSTMAN,可以方便的看到传递参数方式。

1.1GET

第一种,这种方式称呼为Query方式

1.2POST

共四种,分别为form-data、x-www-form-urlencoded、raw、binary,第五种和GET一样,不计算在内

2.实践

2.1 GET

2.1.1 Query

query支持的函数很多,Param函数需要说一下,其使用需要在router上配置

代码

func paramTypeFunc(router *gin.Engine) {
   router.GET("/paramtype/query/:param", paramtype.Query)
}
/**
@date: 2021/5/24
**/
package paramtype
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)
/**
 * @Description: GET Query参数获取实例
 * @param c
 */
func Query(c *gin.Context) {
	//需定义合规结构体
	rawQuery := &RawQuery{}
	c.ShouldBindQuery(rawQuery)
	fmt.Printf("%+v \n", rawQuery)
	param := c.Param("param")
	fmt.Println(param)
	query := c.Query("query")
	fmt.Println(query)
	defaultQuery := c.DefaultQuery("defaultQuery", "no")
	fmt.Println(defaultQuery)
	getQuery, res := c.GetQuery("getQuery")
	fmt.Println(getQuery, res)
	queryArray := c.QueryArray("queryArray")
	fmt.Println(queryArray)
	getQueryArray, res := c.GetQueryArray("getQueryArray")
	fmt.Println(getQueryArray, res)
	queryMap := c.QueryMap("queryMap")
	fmt.Println(queryMap)
	getQueryMap, res := c.GetQueryMap("getQueryMap")
	fmt.Println(getQueryMap)
	c.String(http.StatusOK, "ok")
}

调用

CODE: GET /paramtype/query/this is param?query=this is query&defaultQuery=this is defaultQuery&getQuery=this is getQuery&queryArray=this&queryArray=is&queryArray=queryArray&getQueryArray=this&getQueryArray=is&getQueryArray=getQueryArray&queryMap[1]=this&queryMap[2]=is&queryMap[3]=queryMap&getQueryMap[1]=this&getQueryMap[2]=is&getQueryMap[3]=getQueryMap

HTTP/1.1

Host: 127.0.0.1:8082

Content-Type: application/x-www-form-urlencoded

Cache-Control: no-cache

Postman-Token: e0fdeb2e-78c2-c26d-03ad-a4a6715b3d66

输出

&{Query:this is query}

this is param

this is query

this is defaultQuery

this is getQuery true

[this is queryArray]

[this is getQueryArray] true

map[1:this 2:is 3:queryMap]

map[1:this 2:is 3:getQueryMap]

2.2 POST

2.2.1 form-data

form-data的获取正规正矩。form-data就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来说明文件类型;content-disposition,用来说明字段的一些信息;

如果是文件,可以通过FormFile或者MultipartForm获取文件内容,FormFile获取一个,MultipartForm获取多个。使用SaveUploadedFile存储文件。

代码

/**
@date: 2021/5/25
**/
package paramtype
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)
type PostFormStruct struct {
	GetPostForm string `json:"getPostForm" uri:"getPostForm" form:"getPostForm"`
}
/**
 * @Author: POST form数据获取
 * @Description:
 * @param c
 */
func PostFormData(c *gin.Context) {
	//需定义合规结构体
	postFormStruct := &PostFormStruct{}
	c.ShouldBind(postFormStruct)
	fmt.Printf("%+v \n", postFormStruct)
	postForm := c.PostForm("postForm")
	fmt.Println(postForm)
	defaultPostForm := c.DefaultPostForm("defaultPostForm", "no")
	fmt.Println(defaultPostForm)
	getPostForm, res := c.GetPostForm("getPostForm")
	fmt.Println(getPostForm, res)
	postFormArray := c.PostFormArray("postFormArray")
	fmt.Println(postFormArray)
	getPostFormArray, res := c.GetPostFormArray("getPostFormArray")
	fmt.Println(getPostFormArray, res)
	postFormMap := c.PostFormMap("postFormMap")
	fmt.Println(postFormMap)
	getPostFormMap, res := c.GetPostFormMap("getPostFormMap")
	fmt.Println(getPostFormMap)
	c.String(http.StatusOK, "ok")
}

调用

CODE: POST /paramtype/postformdata HTTP/1.1

Host: 127.0.0.1:8082

Cache-Control: no-cache

Postman-Token: 83c078e3-b7de-d154-dda1-477cc4f2f450

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postForm"

this is postForm

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="defaultPostForm"

this is defaultPostForm

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostForm"

this is getPostForm

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormArray"

this

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormArray"

is

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormArray"

postFormArray

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormArray"

this

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormArray"

is

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormArray"

getPostFormArray

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormMap[1]"

this

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormMap[2]"

is

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="postFormMap[3]"

postFormMap

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormMap[1]"

this

------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormMap[2]"

is ------WebKitFormBoundary7MA4YWxkTrZu0gW

Content-Disposition: form-data; name="getPostFormMap[3]"

getPostFormMap

------WebKitFormBoundary7MA4YWxkTrZu0gW--

输出

&{GetPostForm:this is getPostForm}

this is postForm

this is defaultPostForm

this is getPostForm true

[this is postFormArray]

[this is getPostFormArray] true

map[1:this 2:is 3:postFormMap]

map[1:this 2:is 3:getPostFormMap]

2.2.2 x-www-form-urlencoded

x-www-form-urlencoded是application/x-www-from-urlencoded,将表单内的数据转换为键值对,&分隔。

当form表单的action为get时,浏览器用x-www-form-urlencoded的编码方式,将表单数据编码为 (name1=value1&name2=value2…),然后把这个字符串append到url后面,用?分隔,跳转到这个新的url。

当form表单的action为post时,浏览器将form数据封装到http body中,然后发到server。该格式不能提交文件。

代码

同form-data

调用

CODE: POST /paramtype/postformdata HTTP/1.1

Host: 127.0.0.1:8082

Content-Type: application/x-www-form-urlencoded

Cache-Control: no-cache

Postman-Token: 62ffa49a-e61f-0277-db62-dd9c727e182d

postForm=this+is+postForm&defaultPostForm=this+is+defaultPostForm&getPostForm=this+is+getPostForm&postFormArray=this&postFormArray=is&postFormArray=postFormArray&getPostFormArray=this&getPostFormArray=is&getPostFormArray=getPostFormArray&postFormMap%5B1%5D=this&postFormMap%5B2%5D=is&postFormMap%5B3%5D=postFormMap&getPostFormMap%5B1%5D=this&getPostFormMap%5B2%5D=is&getPostFormMap%5B3%5D=getPostFormMap

输出

同form-data

2.2.3 raw

可以上传任意格式的文本,包括text、json、xml、html等。

raw一般使用Bind和ShouldBind系列函数来获取数据,两者的区别是如果输入数据无效,Bind会将返回状态设置为400,并且中断,ShouldBind就没有这么狠。Bind和ShouldBind根据Content-Type来判断是json/xml/yaml格式,做对应解析。

ShouldBindUri和ShouldBindQuery使用起来有些技巧,代码中对此有标注。

代码

router.POST("/paramtype/raw/:name", paramtype.Raw)
/**
@date: 2021/5/26
**/
package paramtype
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)
type RawStruct struct {
	Id   string
	Text string
}
type RawUri struct {
	Name string `json:"name" uri:"name"`
}
type RawQuery struct {
	Query string `json:"query" uri:"query" form:"query"`
}
/**
 * @Description: POST Raw数据获取
 * @param c
 */
func Raw(c *gin.Context) {
	raw := &RawStruct{}
	c.ShouldBind(raw)
	fmt.Printf("%+v \n", raw)
	//需定义合规结构体
	rawUri := &RawUri{}
	c.ShouldBindUri(rawUri)
	fmt.Printf("%+v \n", rawUri)
	//需定义合规结构体
	rawQuery := &RawQuery{}
	c.ShouldBindQuery(rawQuery)
	fmt.Printf("%+v \n", rawQuery)
	c.String(http.StatusOK, "ok")
}

调用

CODE:

POST /paramtype/raw/I am raw name?query=I am query HTTP/1.1

Host: 127.0.0.1:8082

Content-Type: application/json

Cache-Control: no-cache

Postman-Token: 1c7f46a5-2ea2-36ac-1f9b-29dab2a90d62

{"id":"1","text":"I am raw json"}

输出

&{Id:1 Text:I am raw json}

&{Name:I am raw name}

&{Query:I am query}

2.2.4 binary

相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。

Gin中没有找到相关的函数,文件上传使用的是multipart/form-data,如果大家有相关资料的话,可以告知我一下。

3.请求参数样例

参数

GET:
query:this is query
defaultQuery:this is defaultQuery
getQuery:this is getQuery
queryArray:this
queryArray:is
queryArray:queryArray
getQueryArray:this
getQueryArray:is
getQueryArray:getQueryArray
queryMap[1]:this
queryMap[2]:is
queryMap[3]:queryMap
getQueryMap[1]:this
getQueryMap[2]:is
getQueryMap[3]:getQueryMap
POST:
postForm:this is postForm
defaultPostForm:this is defaultPostForm
getPostForm:this is getPostForm
postFormArray:this
postFormArray:is
postFormArray:postFormArray
getPostFormArray:this
getPostFormArray:is
getPostFormArray:getPostFormArray
postFormMap[1]:this
postFormMap[2]:is
postFormMap[3]:postFormMap
getPostFormMap[1]:this
getPostFormMap[2]:is
getPostFormMap[3]:getPostFormMap

总结

Gin获取输入数据还是挺复杂的,这里简单总结一下:

  1. Get的使用Query、Param系列
  2. Post的form-data和x-www-form-urlencoded使用PostForm系列
  3. Get和Post的数据都可以用Bind、ShouldBind系列,不过结构体的tag需要写正确
  4. 文件上传使用form-data,通过函数FormFile或者MultipartForm

资料

  1. https://geektutu.com/post/quick-go-gin.html Go Gin 简明教程
  2. https://github.com/gin-gonic/gin 源码
  3. https://gin-gonic.com/zh-cn/docs/ 中文文档
  4. https://www.kancloud.cn/shuangdeyu/gin_book/949436 gin中文文档
  5. https://www.kancloud.cn/adapa/gingolang/1124990 Gin框架入门到入土
  6. gin-安装,修改启动端口,get/post 请求参数,模型绑定shouldbind,自定义验证器/表单验证
  7. 一文搞懂gin各种上传文件
  8. postman中 form-data、x-www-form-urlencoded、raw、binary的区别

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:https://shidawuhen.github.io/

往期文章回顾:

招聘

  1. 字节跳动|内推大放送
  2. 字节跳动|今日头条广州服务端研发工程师内推
  3. 字节跳动|抖音电商急招上海前端开发工程
  4. 字节跳动|抖音电商上海资深服务端开发工程师-交易
  5. 字节跳动|抖音电商武汉服务端(高级)开发工程师
  6. 字节跳动|飞书大客户产品经理内推咯
  7. 字节跳动|抖音电商服务端技术岗位虚位以待
  8. 字节跳动招聘专题

设计模式

  1. Go设计模式(12)-桥接模式
  2. Go设计模式(11)-代理模式
  3. Go设计模式(10)-原型模式
  4. Go设计模式(9)-建造者模式
  5. Go设计模式(8)-抽象工厂
  6. Go设计模式(7)-工厂模式
  7. Go设计模式(6)-单例模式
  8. Go设计模式(5)-类图符号表示法
  9. Go设计模式(4)-代码编写优化
  10. Go设计模式(4)-代码编写
  11. Go设计模式(3)-设计原则
  12. Go设计模式(2)-面向对象分析与设计
  13. Go设计模式(1)-语法

语言

  1. 一文搞懂pprof
  2. Go工具之generate
  3. Go单例实现方案
  4. Go通道实现原理
  5. Go定时器实现原理
  6. Beego框架使用
  7. Golang源码BUG追查
  8. Gin框架简洁版
  9. Gin源码剖析

架构

  1. 分页复选设计的坑
  2. 支付接入常规问题
  3. 限流实现2
  4. 秒杀系统
  5. 分布式系统与一致性协议
  6. 微服务之服务框架和注册中心
  7. 浅谈微服务
  8. 限流实现1
  9. CDN请求过程详解
  10. 常用缓存技巧
  11. 如何高效对接第三方支付
  12. 算法总结

存储

  1. MySQL开发规范
  2. Redis实现分布式锁
  3. 事务原子性、一致性、持久性的实现原理
  4. InnoDB锁与事务简析

网络

  1. HTTP2.0基础教程
  2. HTTPS配置实战
  3. HTTPS连接过程
  4. TCP性能优化

工具

  1. GoLand实用技巧
  2. 根据mysql表自动生成go struct
  3. Markdown编辑器推荐-typora

读书笔记

  1. 《毛选》推荐
  2. 原则
  3. 资治通鉴
  4. 敏捷革命
  5. 如何锻炼自己的记忆力
  6. 简单的逻辑学-读后感
  7. 热风-读后感
  8. 论语-读后感
  9. 孙子兵法-读后感

思考

  1. 为动员一切力量争取胜利而斗争
  2. 反对自由主义
  3. 实践论
  4. 评价自己的标准
  5. 服务端团队假期值班方案
  6. 项目流程管理
  7. 对项目管理的一些看法
  8. 对产品经理的一些思考
  9. 关于程序员职业发展的思考
  10. 关于代码review的思考

相关推荐

Dify「模板转换」节点终极指南:动态文本生成进阶技巧(附代码)Jinja2引擎解析

这篇文章是关于Dify「模板转换」节点的终极指南,解析了基于Jinja2模板引擎的动态文本生成技巧,涵盖多源文本整合、知识检索结构化、动态API构建及个性化内容生成等六大应用场景,助力开发者高效利用模...

我用C#造了个AI程序员:自动调试+重构代码实战

在软件开发的世界里,调试和重构代码往往占据了程序员大量的时间。我一直梦想着能有一个智能助手,帮我处理这些繁琐的工作。于是,我决定用C#打造一个AI程序员,让它具备自动调试和重构代码的能力。系统架构设计...

公文自动排版vba代码(公文自动排版vba代码)

Sub公文自动排版()'设置页面参数(单位:厘米)WithActiveDocument.PageSetup.TopMargin=CentimetersToPoints(3.7)&#...

Anthropic最强代码神器:Claude Code系统提示词

最近,在融合Opus-4之后,ClaudeCode的整体能力直线飙升.甚至一度把曾经的最强开发工具——Cursor打的抬不起头来。无论是代码生成的准确度,还是智能补全的丝滑体验,都让人印象深...

使用 Ruff 进行 Python 代码格式化与静态检查

随着Python项目的规模增大,保持一致的代码风格和高质量的代码变得尤为重要。Ruff是一个现代、高性能、支持lint和格式化的Python工具,能帮助你快速发现并修复常见代码问题。本文...

基础语法篇:格式化输出 含完整示例代码

所谓格式化输出就是按照一定格式来输出对应的内容,在Python的语法中格式化输出包含两种:格式化符号、格式化字符串一、格式化符号常用的格式化符号包括%s(将内容转换为字符串,放入占位位置)、%d(将内...

代码整洁如诗!Keil 插件上线,一键格式化代码,告别风格混乱!

引言:代码格式不统一?你的团队还在为“括号位置”吵架吗?嵌入式开发者们,你是否经历过这些抓狂瞬间?代码风格“百花齐放”:同事的代码缩进用空格,你的用Tab,合并时冲突频发!手动调整耗时费力:为了通过C...

[信捷PLC] 信捷PLC之C函数编程(一)

前言写PLC程序,越来越觉得结构化文本编程语言(ST)给PC编程带来的便利,在处理一些数据上,可以写的更加灵活。所以,在项目PLC选型上,我都会优先选择支持结构化文本的PLC。国内有些厂商推出了一些较...

C语言-HelloWorld解析(c语言的helloworld怎么写)

使用VisualStudio2017开发工具新创建一个项目,编写第一个C语言程序。#include<stdio.h>voidmain(){printf("HelloW...

VSCode 配置 C++ 开发环境!教程详解

第一步、安装VSCode应用程序打开VSCode官网,下载对应安装包并默认安装(这里指明:安装路径可以修改)第二步、安装相关插件此时的VSCode仅仅是一个英文文本编辑器,还称不上开发工具,所以需要...

C语言进阶教程:C语言与汇编语言交互

C语言和汇编语言的交互是底层编程和性能优化中的一个重要方面。理解它们如何协同工作,可以帮助开发者更好地控制硬件、优化关键代码段以及理解编译器的行为。为什么需要在C语言中嵌入汇编?尽管C语言已经提供了相...

C语言如何处理平台相关代码(c语言的开发平台)

在进行跨平台C编程时,不可避免地会遇到需要针对不同操作系统或硬件架构编写特定代码的情况。C语言通过预处理器指令,特别是条件编译指令,为我们提供了处理平台相关代码的有效机制。最常用的就是利用预定义的宏(...

C语言:hello world(c语言helloworld代码)

环境:a.初学者建议用“啊哈C”,这款软件简单易装;b.devc.visualstdiod.Vc6.0第一行代码:#include<stdio.h>#<stdio.h&g...

C语言之编译器集合(编写c语言编译器)

C语言有多种不同的编译器,以下是常见的编译工具及其特点:一、主流C语言编译器1.GCC(GNUCompilerCollection)特点:开源、跨平台,支持多种语言(C、C++、Fortran...

适合零基础初学者学习C语言第一课教程,揭开C语言的神秘面纱

一、C语言简介我刚接触编程,首先想要学习的就是C语言,这次我就把我的感悟用我自己理解的文字表述出来,这样对刚学C语言的人来说,才是比较友好的。因为我们都没有C语言的基础,不懂啥是编程,啥事代码。我们...