GoWeb服务器之处理HTTP请求

xiaoxiao2021-03-01  77

一、基本介绍

Go语言的net/http包提供了一系列用于表示HTTP报文的结构,我们可以使用它处理请求和发送相应,其中Request结构代表了客户端发送的请求报文,下面让我们看一下Request结构体

二、获取请求URL

Request结构中的URL字段用于表示请求行中包含的URL,改字段是一个指向url.URL结构的指针,让我们来看一下URL结构 1、Path字段 获取请求的URL 例如:http://localhost:8080/hello?username=admin&password=123456 通过r.URL.Path只能得到 /hello 2、 RawQuery字段 获取请求的URL后面?后面的查询字符串 例如:http://localhost:8080/hello?username=admin&password=123456 通过 r.URL.RawQuery 得到的是username=admin&password=123456 3、案例演示:

package utils import ( "fmt" "net/http" ) func handlerURL(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "发送请求的请求地址是:", r.URL.Path) fmt.Fprintln(w, "发送请求的请求地址的查询字符串是:", r.URL.RawQuery) } func URLDemo() { http.HandleFunc("/url", handlerURL) http.ListenAndServe(":8080", nil) }

三、获取请求头中的信息

通过Request结果中的Header字段用来获取请求头中的所有信息,Header字段的类型是Header类型,而Header类型是一个map[string][]string,string类型的key,string切片类型的值。下面是Header类型及它的方法: 1、获取请求头中的所有信息 r.Header 得到的结果如下:、

map[User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36] Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7] Connection:[keep-alive] Upgrade-Insecure-Requests:[1]]

2、获取请求头中的某个具体属性的值,如获取Accept-Encoding的值 方式一:r.Header[“Accept-Encoding”] i. 得到的是一个字符串切片 ii. 结果

[gzip, deflate, br]

方式二:r.Header.Get(“Accept-Encoding”) i. 得到的是字符串形式的值,多个值使用逗号分隔 ii. 结果

gzip, deflate, br

3、案例演示:

package utils import ( "fmt" "net/http" ) func handlerHeader(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "发送请求的请求头信息:", r.Header) fmt.Fprintln(w, "请求头中Accept-Encoding的信息是:", r.Header["Accept-Encoding"]) fmt.Fprintln(w, "请求头中Accept-Encoding的属性值是:", r.Header.Get("Accept-Encoding")) } func HeaderDemo() { http.HandleFunc("/header", handlerHeader) http.ListenAndServe(":8080", nil) }

四、获取请求体中的信息

请求和响应的主体都是有Request结构中的Body字段表示,这个字段的类型是io.ReadCloser接口,该接口包含了Reader接口和Closer接口,Reader接口拥有Read方法,Closer接口拥有Close方法 1、 由于GET请求没有请求体,所以我们需要在HTML页面中创建一个form表单,通过指定method=”post”来发送一个POST请求。 1) 表单

<form action="http://localhost:8080/getBody" method="POST"> 用户名:<input type="text" name="username" value="hanzong"><br/> 密码:<input type="password" name="password" value="666666"><br/> <input type="submit"> </form>

2) 服务器处理请求的代码

package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { //获取内容的长度 length := r.ContentLength //创建一个字节切片 body := make([]byte, length) //读取请求体 r.Body.Read(body) fmt.Fprintln(w, "请求体中的内容是:", string(body)) } func main() { http.HandleFunc("/getBody", handler) http.ListenAndServe(":8080", nil) }

3) 在浏览器上显示的结果 请求体中的内容是: username=hanzong&password=666666 2、案例:

package utils import ( "fmt" "net/http" ) func handlerBody(w http.ResponseWriter, r *http.Request) { //获取请求体重内容的长度 len := r.ContentLength //创建byte切片 body := make([]byte, len) //将请求体中的内容读到body中 r.Body.Read(body) //在浏览器中显示请求体中的内容 fmt.Fprintln(w, "请求体中的内容有:", string(body)) } func BodyDemo() { http.HandleFunc("/body", handlerBody) http.ListenAndServe(":8080", nil) }

五、获取请求参数

下面我们就通过net/http库中的Request结构的字段以及方法获取请求URL后面的请求参数以及form表单中提交的请求参数 1、Form字段 1) 类型是url.Values类型,Form是解析好的表单数据,包括URL字段的query参数和POST或PUT的表单数据。 2) Form字段只有在调用Request的ParseForm方法后才有效。在客户端,会忽略请求中的本字段而使用Body替代

3) 获取的表单中提交的请求参数(username和password) 代码

func handler(w http.ResponseWriter, r *http.Request) { //解析表单 r.ParseForm() //获取请求参数 fmt.Fprintln(w, "请求参数为:", r.Form) }

注意:在执行r.Form之前一定要调用ParseForm方法 结果 请求参数为: map[password:[666666] username:[hanzong]]

4) 如果对form表单做一些修改,在action属性的URL后面也添加相同的请求参数,如下:

<form action="http://localhost:8080/getBody?username=admin&pwd=123456" method="POST"> 用户名:<input type="text" name="username" value="hanzong"><br/> 密码:<input type="password" name="password" value="666666"><br/> <input type="submit"> </form>

5) 则执行结果如下: 请求参数为: map[username:[hanzong admin] password:[666666] pwd:[123456]] 我们发现:表单中的请求参数username和URL中的请求参数username都获取到了,而且表单中的请求参数的值排在URL请求参数值的前面 如果此时我们只想获取表单中的请求参数该怎么办呢?那就需要使用Request结构中的PostForm字段

2、PostForm字段 1)类型也是 url.Values 类型,用来获取表单中的请求参数 将r.Form改为r.PostForm之后的代码

func handler(w http.ResponseWriter, r *http.Request) { //解析表单 r.ParseForm() //获取请求参数 fmt.Fprintln(w, "请求参数为:", r.PostForm) }

2)结果 请求参数为: map[username:[hanzong] password:[666666]]

3)但是PostForm字段只支持application/x-www-form-urlencoded编码,如果form表单的enctype属性值为multipart/form-data,那么使用PostForm字段无法获取表单中的数据,此时需要使用MultipartForm字段 说明:form表单的enctype属性的默认值是application/x-www-form-urlencoded编码,实现上传文件时需要讲该属性的值设置为multipart/form-data编码格式

3、FormValue方法和PostFormValue方法 1) FormValue方法 a) 可以通过FormValue方法快速地获取某一个请求参数,该方法调用之前会自动调用ParseMultipartForm和ParseForm方法对表单进行解析 代码

func handler(w http.ResponseWriter, r *http.Request) { //获取请求参数 fmt.Fprintln(w, "请求参数username的值为:", r.FormValue("username")) }

结果 请求参数username的值为: hanzong

2) PostFormValue方法 a) 可以通过PostFormValue方法快速地获取表单中的某一个请求参数,该方法调用之前会自动调用ParseMultipartForm和ParseForm方法对表单进行解析 代码

func handler(w http.ResponseWriter, r *http.Request) { //获取请求参数 fmt.Fprintln(w, "请求参数username的值为:", r.PostFormValue("username")) }

结果 请求参数username的值为: hanzong

4、MultipartForm字段 为了取得multipart/form-data编码的表单数据,我们需要用到Request结构的ParseMultipartForm方法和MultipartForm字段,我们通常上传文件时会将form表单的enctype属性值设置为multipart/form-data 1) 表单

<form action="http://localhost:8080/upload" method="POST" enctype="multipart/form-data"> 用户名:<input type="text" name="username" value="hanzong"><br/> 文件:<input type="file" name="photo" /><br/> <input type="submit"> </form>

2) 后台处理请求代码

package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { //解析表单 r.ParseMultipartForm(1024) //打印表单数据 fmt.Fprintln(w, r.MultipartForm) } func main() { http.HandleFunc("/upload", handler) http.ListenAndServe(":8080", nil) }

3) 浏览器显示结果

&{map[username:[hanzong]] map[photo:[0xc042126000]]}

结果中有两个映射,第一个映射映射的是用户名;第二个映射的值是一个地址

MuiltipartForm字段的类型为 *multipart.Form,multipart包下Form结构的指针类型

打开上传的文件

func handler(w http.ResponseWriter, r *http.Request) { //解析表单 r.ParseMultipartForm(1024) fileHeader := r.MultipartForm.File["photo"][0] file, err := fileHeader.Open() if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } }

4、 FormFile方法 net/http提供的FormFile方法可以快速的获取被上传的文件,但是只能处理上传一个文件的情况。

代码

func handler(w http.ResponseWriter, r *http.Request) { file, _, err := r.FormFile("photo") if err == nil { data, err := ioutil.ReadAll(file) if err == nil { fmt.Fprintln(w, string(data)) } } }

5、案例:

package utils import ( "fmt" "net/http" ) func handlerParameter(w http.ResponseWriter, r *http.Request) { /*1、Form字段*/ //解析表单,在调用r.Form之前必须执行该操作 r.ParseForm() //获取请求参数 //如果form表单的action属性的URL地址中也有与form表单参数名相同的请求参数, //那么参数值都可以得到,并且form表单中的参数值在ULR的参数值的前面 fmt.Fprintln(w, "请求参数有:", r.Form) /*2、PostForm字段*/ fmt.Fprintln(w, "POST请求的form表单中的请求参数有:", r.PostForm) /*3、FormValue方法和PostFormValue方法*/ //通过直接调用FormValue方法和PostFormValue方法直接获取请求参数的值 fmt.Fprintln(w, "URL中的user请求参数的值是:", r.FormValue("name")) fmt.Fprintln(w, "Form表单中的username请求参数的值是:", r.PostFormValue("username")) } /*MultipartForm字段*/ func handlerMultipartForm(w http.ResponseWriter, r *http.Request) { //解析表单 r.ParseMultipartForm(1024) //打印表单数据 fmt.Fprintln(w, r.MultipartForm) } func ParameterDemo() { http.HandleFunc("/paramter", handlerParameter) http.HandleFunc("/multipart", handlerMultipartForm) http.ListenAndServe(":8080", nil) }

六、 给客户端响应

前面我们一直说的是如何使用处理器中的 *http.Request 处理用户的请求,下面我们来说一下如何使用 http.ResponseWriter 来给用户响应 1、 给客户端响应一个字符串

处理器中的代码 func handler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("你的请求我已经收到")) } 浏览器中的结果 你的请求我已经收到 响应报文中的内容 HTTP/1.1 200 OK Date: Fri, 10 Aug 2018 01:09:27 GMT Content-Length: 27 Content-Type: text/plain; charset=utf-8

2、给客户端响应一个HTML页面 1) 处理器中的代码

func handler(w http.ResponseWriter, r *http.Request) { html := `<html> <head> <title>测试响应内容为网页</title> <meta charset="utf-8"/> </head> <body> 我是以网页的形式响应过来的! </body> </html>` w.Write([]byte(html)) }

2) 浏览器中的结果

我是以网页的形式响应过来的!

通过在浏览器中右键→查看网页代码发现确实是一个html页面 3) 响应报文中的内容

HTTP/1.1 200 OK Date: Fri, 10 Aug 2018 01:26:58 GMT Content-Length: 194 Content-Type: text/html; charset=utf-8

3、给客户端响应JSON格式的数据 1) 处理器端代码

func handler(w http.ResponseWriter, r *http.Request) { //设置响应头中内容的类型 w.Header().Set("Content-Type", "application/json") user := User{ ID: 1, Username: "admin", Password: "123456", } //将user转换为json格式 json, _ := json.Marshal(user) w.Write(json) }

2) 浏览器中的结果

{"ID":1,"Username":"admin","Password":"123456"}

3) 响应报文中的内容

HTTP/1.1 200 OK Content-Type: application/json Date: Fri, 10 Aug 2018 01:58:02 GMT Content-Length: 47

4、让客户端重定向 1) 处理器端代码

func handler(w http.ResponseWriter, r *http.Request) { //以下操作必须要在WriteHeader之前进行 w.Header().Set("Location", "https:www.baidu.com") w.WriteHeader(302) }

2) 响应报文中的内容

HTTP/1.1 302 Found Location: https:www.baidu.com Date: Fri, 10 Aug 2018 01:45:04 GMT Content-Length: 0 Content-Type: text/plain; charset=utf-8

5、案例:

package utils import ( "encoding/json" "goweb_code/web_Request/code/model" "net/http" ) /*客户端响应*/ func handlerHTML(w http.ResponseWriter, r *http.Request) { html := `<html> <head> <title>测试响应内容为网页</title> <meta charset="utf-8"/> </head> <body> 我是以网页的形式响应过来的! </body> </html>` w.Write([]byte(html)) } /*客户端响应——JSON*/ func handlerJSON(w http.ResponseWriter, r *http.Request) { //设置响应内容的类型 w.Header().Set("Content-Type", "application/json") //创建User user := model.User{ ID: 1, Username: "admin", Password: "123456", Email: "admin@atguigiu.com", } //将User转换为Json个数 json, _ := json.Marshal(user) //将json格式的数据响应给客户端 w.Write(json) } /*客户端响应——重定向*/ func handlerLocation(w http.ResponseWriter, r *http.Request) { //设置响应头中的Location属性 w.Header().Set("Location", "https://www.baidu.com") //设置响应的状态码 w.WriteHeader(302) } func ResponeDemo() { http.HandleFunc("/html", handlerHTML) http.HandleFunc("/json", handlerJSON) http.HandleFunc("/location", handlerLocation) http.ListenAndServe(":8080", nil) }
转载请注明原文地址: https://www.6miu.com/read-4467997.html

最新回复(0)