首页 > 其他分享 >gin基础-2.响应与请求

gin基础-2.响应与请求

时间:2024-09-20 15:54:41浏览次数:8  
标签:code 请求 响应 func msg gin data name

响应

gin提供了非常多的响应方法

例如 字符串、json、html等

json响应

现在大部分的前后端交互都是以json为主,所以gin中最常用的就是json响应

它的用法非常简单

c.JSON(200, gin.H{
  "code": 0,
  "msg": "ok",
})

但是我们都会对其进行一番封装,例如标准响应格式 code,data,msg

前端可以判断code的值来确定操作是否成功

不过code的定义就是每家公司都有不同的定义了

我比较习惯于code=0为操作成功的状态码,非0值就是具体的错误码,这样可以方便定位错误

例如 code=1001 是权限错误,code=1002 是资源不存在等

如何封装?

package res

import "github.com/gin-gonic/gin"

type Response struct {
  Code int    `json:"code"`
  Data any    `json:"data"`
  Msg  string `json:"msg"`
}

type Code int

const (
  RoleErrCode    Code = 1001
  NetworkErrCode Code = 1002
)

var codeMap = map[Code]string{
  RoleErrCode:    "权限错误",
  NetworkErrCode: "网络错误",
}

func init() {
  // 可能是一个
}

func response(c *gin.Context, r Response) {
  c.JSON(200, r)
}

func Ok(c *gin.Context, data any, msg string) {
  response(c, Response{
    Code: 0,
    Data: data,
    Msg:  msg,
  })
}

func OkWithData(c *gin.Context, data any) {
  Ok(c, data, "成功")
}

func OkWithMsg(c *gin.Context, msg string) {
  Ok(c, map[string]any{}, msg)
}

func Fail(c *gin.Context, code int, data any, msg string) {
  response(c, Response{
    Code: code,
    Data: data,
    Msg:  msg,
  })
}
func FailWithMsg(c *gin.Context, msg string) {
  response(c, Response{
    Code: 7,
    Data: nil,
    Msg:  msg,
  })
}
func FailWithCode(c *gin.Context, code Code) {
  // 去找code对应的msg
  msg, ok := codeMap[code]
  if !ok {
    msg = "未知错误"
  }
  response(c, Response{
    Code: int(code),
    Data: nil,
    Msg:  msg,
  })
}


封装之后,使用就很简单了

res.OkWithMsg(c, "登陆成功")
res.OkWithData(c, map[string]any{
      "name": "枫枫",
    })
res.FailWithMsg(c, "参数错误")

html响应

使用LoadHTMLGlob加载一个目录下的所有html文件

也可以使用LoadHTMLFiles加载单个html文件

load之后,下面才能用这个文件名

package main

import "github.com/gin-gonic/gin"

func main() {
  r := gin.Default()
  // 加载模板 只有这里加载了模板,下面才能用
  r.LoadHTMLGlob("templates/*")
  //r.LoadHTMLFiles("templates/index.html")
  r.GET("", func(c *gin.Context) {
    c.HTML(200, "index.html", nil)
  })
  r.Run(":8080")
}

HTML的第三个参数是可以向HTML中传递数据

但是现在都是前后端分离的时代了,也很少使用后端返回模板了,知道怎么用就好

c.HTML(200, "index.html", map[string]any{
    "title": "这是网页标题",
  })

html文件中使用

<title>{{.title}}</title>

其实借助这个功能,可以很方便的修改网站的标题和logo

简单的扩展一下

关于部署:

  1. 前端单独部署,后端单独部署
  2. 前端打包之后,后端统一部署

响应文件

用于浏览器直接请求这个接口唤起下载

c.Header("Content-Type", "application/octet-stream")              // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
c.Header("Content-Disposition", "attachment; filename=3.文件下载.go") // 用来指定下载下来的文件名
c.File("3.文件下载.go")
  1. 要设置Content-Type,唤起浏览器下载
  2. 只能是get请求

前端请求后端接口,然后唤起浏览器下载

c.Header("fileName", "xxx.png")
c.Header("msg", "文件下载成功")
c.File("uploads/12.png")

前端唤起浏览器下载的本质

<a href="文件地址" download="文件名">文件下载</a>
async downloadFile(row) {
   this.$http({
      method: 'post',
      url: 'file/upload',
      data:postData,
      responseType: "blob"
   }).then(res => {
      const _res = res.data
      let blob = new Blob([_res], {
            type: 'application/png'
          });
      let downloadElement = document.createElement("a");
      let href = window.URL.createObjectURL(blob); //创建下载的链接
      downloadElement.href = href;
      downloadElement.download = res.headers["fileName"]; //下载后文件名
      document.body.appendChild(downloadElement);
      downloadElement.click(); //点击下载
      document.body.removeChild(downloadElement); //下载完成移除元素
      window.URL.revokeObjectURL(href); //释放掉blob对象
    })}

最好的做法

调下载接口的请求,后端不返回实际文件内容,而是生成一个临时下载地址

前端构造a标签,再请求这个接口唤起浏览器下载

静态文件

r.Static("static", "static") // 第一个参数是别名,第二个才是实际路径
r.StaticFile("abcd", "static/abc.txt")

静态文件的路径,不能再被路由使用了

 

请求

查询参数

?key=xxx&name=xxxx&name=yyyy 这种就被称为查询参数

查询参数不是GET请求专属的

name := c.Query("name")
age := c.DefaultQuery("age", "25")
keyList := c.QueryArray("key")
fmt.Println(name, age, keyList)

例如请求 ?name=fengfeng&age=123&key=123&key=124,输出为:

fengfeng 123 [123 124]

动态参数

用户的个人信息页面,他的路径

/users?id=123 // 查询参数的模式
/users/123 // 动态参数模式
r.GET("users/:id", func(c *gin.Context) {
  userID := c.Param("id")
  fmt.Println(userID)
})

表单参数

一般就是专指form表单

name := c.PostForm("name")
age, ok := c.GetPostForm("age")
fmt.Println(name)
fmt.Println(age, ok)

文件上传

r.POST("users", func(c *gin.Context) {
  fileHeader, err := c.FormFile("file")
  if err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println(fileHeader.Filename) // 文件名
  fmt.Println(fileHeader.Size)     // 文件大小,单位是字节

  file, _ := fileHeader.Open()
  byteData, _ := io.ReadAll(file)

  err = os.WriteFile("xxx.jpg", byteData, 0666)
  fmt.Println(err)
})

还有一种简单方式

err = c.SaveUploadedFile(fileHeader, "uploads/xxx/yyy/"+fileHeader.Filename)
fmt.Println(err)

多文件上传

  r.POST("users", func(c *gin.Context) {
    form, err := c.MultipartForm()
    if err != nil {
      fmt.Println(err)
      return
    }
    for _, headers := range form.File {
      for _, header := range headers {
        c.SaveUploadedFile(header, "uploads/"+header.Filename)
      }
    }
  })

关于接口测试工具

postman

apifox

注意:接口测试工具能走通的,前端请求不一定可以走通

  1. get请求带请求体
  2. ws加请求头

原始内容

不同的请求体对应的原始内容

body阅后即焚问题解决

byteData, _ := io.ReadAll(c.Request.Body)
fmt.Println(string(byteData))
// 读了之后,body就没了,阅后即焚
c.Request.Body = io.NopCloser(bytes.NewReader(byteData))

form-data

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

枫枫
----------------------------853882779395683818968400
Content-Disposition: form-data; name="age"

1234
----------------------------853882779395683818968400--

对应的分隔符就是

Content-Type:[multipart/form-data; boundary=--------------------------052455317193517003536866]

x-www-form-urlencoded

url编码

name=%E6%9E%AB%E6%9E%AB&age=1234

json

{
    "name": "枫枫",
    "age": 23
}

 

标签:code,请求,响应,func,msg,gin,data,name
From: https://blog.csdn.net/csdngzy/article/details/142387723

相关文章

  • 编译安装nginx
    Nginx官方定义了Mainline、Stable、Legacy三种版本Mainlineversion(主线版本)该版本包含最新的功能和bug修复,被视为开发版,即正在活跃开发中的版本。其版本号通常为单数,这个版本的更新较快,可能会引入新的功能和修复,但也可能存在尚未解决的bug。Stableversion(稳定版本)最新稳......
  • vue3中设置响应式对象和数组
    <template><divclass="persion"><h2>姓名:{{name}}</h2><h2>年龄:{{age}}</h2><h2>性别:{{sex}}</h2><button@click="nameTel">点击姓名</button>......
  • nginx代理grafana
    nginx代理grafana背景我自己nginx不怎么会,然后我的生产环境已经不允许我使用【/】这个根路径了。我只能为其加上一个路径来解析。网络拓扑示意图如图所示,我想在运维电脑上请求grafanaweb。但是这中间夹了几层,目前已知防火墙是放通了负载均衡的80端口到运维电脑上,nginx和负载......
  • nginx: 分析最慢的url(日志中增加请求时长)
    一,设置nginx的日志格式:1,编辑nginx.conf[root@blogconf]#vinginx.conf说明:比默认设置只是在末尾增加了$request_time一项log_formatmain'$remote_addr-$remote_user[$time_local]"$request"''$status$body_bytes_sent"......
  • Advanced .Net Debugging 11:完结篇
    一、介绍这是我的《Advanced.NetDebugging》这个系列的第十一篇文章,也是这个系列的最后一篇了。我已经把原书的前八章内容全部写完了,本来打算继续写第九章和第十章的内容,后来我放弃逐章逐节的编写,选择了将两章的内容进行过滤后,合为一篇,只把重要的内容包含进来的做法。原......
  • gin错误处理,和事务处理
    packagemainimport( "fmt" "github.com/gin-gonic/gin" _"github.com/go-sql-driver/mysql" "gorm.io/driver/mysql" "gorm.io/gorm" "net/http")varDb*gorm.DBtypeDade1struct{ Idint......
  • AJAX请求的步骤解析与优化方法
    ajax的请求过程1、新建ajax对象:    IE6不兼容newXMLHttpRequest();    IE6下,ajax对象的兼容方法:        window判断的方法:            varxhr=null;            if(window.XMLHttpRequest){    xhr=newXMLHttpReq......
  • 【集成学习|Bagging、Boosting 和 Stacking】三种常见的集成学习算法的联系与区别?以及
    【集成学习|Bagging、Boosting和Stacking】三种常见的集成学习算法的联系与区别?以及如何实现?【集成学习|Bagging、Boosting和Stacking】三种常见的集成学习算法的联系与区别?以及如何实现?附代码学习文章目录【集成学习|Bagging、Boosting和Stacking】三种常见的......
  • Vue 目录树正常跳转,浏览器新增页面地址栏输入后created函数请求不走完
    在vue树中开发当created()涉及到多个接口请求的时候,一般我们都是用来渲染页面或者给变量初始化,在实际开发中我遇到了浏览器新增页面用地址直接访问页面数据以默认值展示导致报错,当发现created()涉及多个请求赋初值的情况,将请求用{}包起来保证顺序执行,当每个请求是独立的就会有异步......
  • uniapp 封装请求方法
    目录uni.request()封装uni.showLoading()封装使用request() 方法uni.request()封装//request.jsconstBASE_URL='https://tea.qingnian8.com/api';//请求函数exportconstrequest=(option={})=>{ //解构并赋初始值 let{ url, data={}, ......