当前位置: 首页 > news >正文

Go Web如何处理Web请求?

Web应用程序最重要的功能,就是接收来自客户端(一般是浏览器或APP)发起的请求,根据请求方法与类型返回静态HTML页面或动态生成客户端想要的数据,而Go语言中net/http已经在处理请求数据方面做了很好的封装,使得用Go代码处理Web请求的数据并生成响应数据变得非常简单,下面一起学习一下吧!

Web请求

我们知道,一个HTTP事务由请求响应构成,这篇文章中,我们单讲有关Web请求的部分。

客户端一般是通过一个URL向服务器发起请求,最简单的比如在浏览地址栏输入:juejin.im。

Chrome浏览器输入掘鑫url

每一个Web请求都包括三个部分:请求行请求头请求实体

请求方法

请求方法请求行当中,HTTP协议支持多种请求方法(method),主要有七种:

GET,POST,PUT,HEADER,PATCH,DELETE,OPTIONS

其中Web开发最常见就是GET方法和POST方法,使用GET方法发起的请求,没有请求实体(body),因些请求的数据一般只能通过URL中的查询参数(query)传给服务端,而使用POST方法的请求则会携带请求实体,在请求实体中带有传给服务端的数据。

Content-Type

Content-Type请求头部(Header)中一个用于指请求实体类型的内容头部,在请求或响应用于指请求实体到底存放什么样的数据,所以只有会推带请求实体的方法起作用,如POST方法。

在一般Web开发中,Content-Type最常用取值有下面四种:

  1. application/json:JSON数据

  2. application/x-www-form-urlencoded:form表单请求使用的类型,在发送前会编码所有字符

  3. multipart/form-data:不对字符编码,一般用于文件上传

  4. text/html:一般用于响应中的响应头,告诉客户端返回的是HTML文档。

查询参数(query)

查询参数是URL中?后面跟着的部分,比如在掘金的搜索框中输入:Go,我们会看到浏览器的地址栏变成:

juejin.im/search?quer…

查询参数就是指query=Go&type=1,查询参数由&分隔开,这是GET方法携带数据的方式,Go语言中支持获取查询参数部分的参数。

请求实体(body)

请求实体是一次Web请求中数据携带部分,一般只有POST请求才有这个部分,服务器由Content-Type首部来判断请求实体的内容编码格式,如果想向服务器发送大量数据,一般都用POST请求。

Go处理Web请求数据

在Go语言中,使用http.Request结构来处理http请求的数据,在我们定义处理请求的方法,会传入http.Request的实例,如下代码中request就是代表一个请求的实例。

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    //使用request可以获取http请求的数据
})
复制代码

在golang官方文档中,可以看到http.Request的包外可访问方法列表:

http.Request方法列表

下面是http.Request公开可访问的字段

type Request struct {
        Method string //方法:POST,GET...
        URL *url.URL //URL结构体
        Proto      string // 协议:"HTTP/1.0"
        ProtoMajor int    // 1
        ProtoMinor int    // 0
        Header Header    //头部信息
        Body io.ReadCloser //请求实体
        GetBody func() (io.ReadCloser, error) // Go 1.8
        ContentLength int64  //首部:Content-Length
        TransferEncoding []string
        Close bool           //是否已关闭
        Host string          //首部Host
        Form url.Values      //参数查询的数据
        PostForm url.Values // application/x-www-form-urlencoded类型的body解码后的数据
        MultipartForm *multipart.Form //文件上传时的数据
        Trailer Header
        RemoteAddr string          //请求地址
        RequestURI string          //请求的url地址
        TLS *tls.ConnectionState
        Cancel <-chan struct{} // 
        Response *Response //      响应数据
}
复制代码

获得请求头(Header)

对于常用的请求头部信息,http.Request结构有对应的字段和方法,如下所示:

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    request.RemoteAddr
    request.RequestURI
    request.ContentLength 
    request.Proto
    request.Method 
    request.Referer()
    request.UserAgent()
})
复制代码

当然,其他的首页,可以通过request.Header字段来获取,request.Header的定义如下所示:

type Header map[string][]string
复制代码

也就是说,request.Header是一个的类型是map,另外request.Header也提供相应的方法,如下所示:

也就是说,我们除了使用上面的方法获取头部信息外,也可以使用request.Header来获取,示例:

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    request.Header.Get("Content-Type")//返回的是string
    request.Header["Content-Type"] //返回的是[]string
})

复制代码

获取查询参数(Query)

如何获取查询参数(url中?后面使用&分隔的部分)呢?可以使用request.FormValue(key)方法获取查询参数,其中key为参数的名称,代码如下:

package main
import (
	"fmt"
	"net/http"
)
func main() {
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        username := request.FormValue("username")
        gender := request.FormValue("gender")
        fmt.Fprintln(writer,fmt.Sprintf("用户名:%s,性别:%s",username,gender))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
复制代码

在Postman输入http://localhost:8080/hello?username=test&gender=男

获取表单信息(Form)

我们说获取表单信息,一般是指获取Content-Type是application/x-www-form-urlencodedmultipart/form-data时,请求实体中的数据,如果你有做传统网页中的表单提交数据的经历,相信对这两种提交数据的方式应该是熟悉的,而multipart/form-data一般是用来上传文件的。

application/x-www-form-urlencoded

获取Content-Type为application/x-www-form-urlencoded时提交上来的数据,可以使用request.PostForm字段request.Form和request.PostFormValue(key)方法获取,但必须先调用request.ParseForm()将数据写入request.PostForm字段中。

步骤为:

  1. 使用request.ParseForm()函数解析body参数,这时会将参数写入Form字段和PostForm字段当中。
  2. 使用request.Form、request.PostForm或request.PostFormValue(key)都可以获取

注意,request.Form和request.PostForm的类型url.Values,结构定义如下:

type Values map[string][]string
复制代码

示例如下:

package main
import (
	"fmt"
	"net/http"
)
func main(){
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        err := request.ParseForm()
        if err != nil{
        fmt.Fprintln(writer,"解析错误")
        }
        username1 := request.PostForm["username"][0]
        username2 := request.PostFormValue("username")
        username3 := request.Form["username"][0]
        fmt.Fprintln(writer,fmt.Sprintf("username1:%s,username2:%s,usernam3:%s",username1,username2,username3))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
复制代码

使用Postman输入http://localhost:8080/hello,结果如下:

multipart/form-data

获取Content-Typemultipart/form-data时提交上来的数据,步骤如下:

  1. 使用request.ParseMultipartForm(maxMemory),解析参数,将参数写入到MultipartForm字段当中,其中maxMemory为上传文件最大内存。
  2. 使用request.FormFile(文件域),可以获取上传的文件对象:multipart.File
  3. 除了文件域,其中参数可以从request.PostForm字段获取,注意,此时不需要再调用request.ParseForm()了。
package main
import (
	"fmt"
	"net/http"
)
func main() {
    http.HandleFunc("/upload", func(writer http.ResponseWriter, request *http.Request) {
        err := request.ParseMultipartForm(32 << 20)
        if err != nil {
            fmt.Fprintln(writer,"文件上传错误")
            return
        }
        fmt.Println(request.FormFile("file"))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
复制代码

总结

上面简单地介绍了使用Go语言如何获取http请求提交上来的数据,重点为获了表单数据,但其实在现在前后端分离开发趋势和APP开发中,Content-Type指application/json是更常见的数据提交方式,以后有空可以学一下。

相关文章:

  • Maven之setting.xml 配置详解
  • 说说我为什么看好Spring Cloud Alibaba
  • Selenium 人工智能操作工具
  • 雷军:明后年会迎来5G手机的全面换机潮
  • Arts 第三周(4/1 ~ 4/7)
  • 3.31
  • 经常被问到的十个 Java 面试题?你Get了吗?
  • linux gcc 静态 动态链接库
  • Apache基金会总结RocketMQ:中国70%的银行核心业务已采用,国内技术人员贡献明显增多...
  • 如何在Kubernetes上运行Apache Flink
  • go package包的使用
  • GC参考手册 —— GC 算法(基础篇)
  • java B2B2C Springboot电子商城系统-路由网关(zuul)
  • 我们用5分钟写了一个跨多端项目
  • Ubuntu MATE 推出树莓派版本
  • 10个确保微服务与容器安全的最佳实践
  • 30秒的PHP代码片段(1)数组 - Array
  • Android Studio:GIT提交项目到远程仓库
  • const let
  • HTTP--网络协议分层,http历史(二)
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Python_OOP
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • React组件设计模式(一)
  • SwizzleMethod 黑魔法
  • 解析 Webpack中import、require、按需加载的执行过程
  • 如何设计一个比特币钱包服务
  • 首页查询功能的一次实现过程
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​iOS实时查看App运行日志
  • # 飞书APP集成平台-数字化落地
  • #QT(串口助手-界面)
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (27)4.8 习题课
  • (4.10~4.16)
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (原創) 博客園正式支援VHDL語法著色功能 (SOC) (VHDL)
  • (转)使用VMware vSphere标准交换机设置网络连接
  • .NET Core 成都线下面基会拉开序幕
  • .Net CoreRabbitMQ消息存储可靠机制
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .Net IE10 _doPostBack 未定义
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .Net6使用WebSocket与前端进行通信
  • /bin/bash^M: bad interpreter: No such file or directory
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @Autowired和@Resource的区别
  • @Not - Empty-Null-Blank
  • [ vulhub漏洞复现篇 ] ThinkPHP 5.0.23-Rce
  • [20181219]script使用小技巧.txt
  • [bug总结]: Feign调用GET请求找不到请求体实体类