欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

goweb- 对请求的处理

程序员文章站 2022-03-21 17:40:14
对请求的处理 Go 语言的 net/http 包提供了一系列用于表示 HTTP 报文的结构,我们可以使用它 处理请求和发送相应,其中 Request 结构代表了客户端发送的请求报文,下面让我们看 一下 Request 结构体 获取请求 URL Request 结构中的 URL 字段用于表示请求行中包 ......

对请求的处理

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

获取请求 url

request 结构中的 url 字段用于表示请求行中包含的 url,改字段是一个指向
url.url 结构的指针

 path 字段

  • 获取请求的 url

  • 例如:

注: 通过 r.url.path 只能得到 /hello

rawquery 字段

  • 获取请求的 url 后面?后面的查询字符串

  • 例如:

注: 通过 r.url.rawquery 得到的是 username=admin&password=123456

获取请求头中的信息

通过 request 结果中的 header 字段用来获取请求头中的所有信息,header 字段
的类型是 header 类型,而 header 类型是一个 map[string][]string,string 类型的 key,
string 切片类型的值。

获取请求头中的所有信息

  • 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,ima
ge/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]]

获取请求头中的某个具体属性的值,如获取 accept-encoding 的值

  • 方式一:r.header[“accept-encoding”]

    • 得到的是一个字符串切片
    • 结果[gzip, deflate, br]
  • 方式二:r.header.get(“accept-encoding”)

    • 得到的是字符串形式的值,多个值使用逗号分隔
    • 结果gzip, deflate, br

获取请求体中的信息

请求和响应的主体都是有 request 结构中的 body 字段表示,这个字段的类型是
io.readcloser 接口,该接口包含了 reader 接口和 closer 接口,reader 接口拥有 read
方法,closer 接口拥有 close 方法

通过指定 method=”post”来发送一个 post 请求

由于 get 请求没有请求体,所以我们需要在 html 页面中创建一个 form 表单,通
过指定 method=”post”来发送一个 post 请求

  • 表单
<html>
    <head>
        <meta charset="utf-8"/>
    </head>
    <body>
        <form action="http://localhost:8080/getbody" method="post" enctype="multipart/form-data">
            用户名:<input type="text" name="username" /><br/>
            密码:<input type="password" name="password" /><br/>
            <input type="submit" />
        </form>
    </body>
</html>
  • 服务器处理请求的代码
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)
}
  • 在浏览器上显示的结果

    • 请求体中的内容是: username=hanzong&password=666666

获取请求参数

下面我们就通过 net/http 库中的 request 结构的字段以及方法获取请求 url 后面
的请求参数以及 form 表单中提交的请求参数

form 字段

1) 类型是 url.values 类型,form 是解析好的表单数据,包括 url 字段的 query
参数和 post 或 put 的表单数据。
2) form 字段只有在调用 request 的 parseform 方法后才有效。在客户端,会忽
略请求中的本字段而使用 body 替代
1) 获取表单中提交的请求参数(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]]
  • d) 如果对 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>

则执行结果如下:

请求参数为:map[username:[hanzong admin] password:[666666] pwd:[123456]]

  • 我们发现:表单中的请求参数 username 和 url 中的请求参数
    username 都获取到了,而且表单中的请求参数的值排在 url 请求参
    数值的前面
  • 如果此时我们只想获取表单中的请求参数该怎么办呢?那就需要使
    用 request 结构中的 postform 字段

postform 字段

1) 类型也是 url.values 类型,用来获取表单中的请求参数

  • 将 r.form 改为 r.postform 之后的代码
func handler(w http.responsewriter, r *http.request) {
//解析表单
r.parseform()
//获取请求参数
fmt.fprintln(w, "请求参数为:", r.postform)
}
  • 结果

请求参数为:map[username:[hanzong] password:[666666]]

2) 但是 postform 字段只支持 application/x-www-form-urlencoded 编码,如果
form 表单的 enctype 属性值为 multipart/form-data,那么使用 postform 字段
无法获取表单中的数据,此时需要使用 multipartform 字段

  • 说明:form 表单的 enctype 属性的默认值是 application/x-www-form-
    urlencoded 编 码 , 实 现 上 传 文 件 时 需 要 讲 该 属 性 的 值 设 置 为
    multipart/form-data 编码格式

formvalue 方法和 e postformvalue 方法

formvalue 方法

a) 可以通过 formvalue 方法快速地获取某一个请求参数,该方法调用之前
会自动调用 parsemultipartform 和 parseform 方法对表单进行解析

  • 代码
func handler(w http.responsewriter, r *http.request) {
//获取请求参数
fmt.fprintln(w, "请求参数username的值为:", r.formvalue("username"))
}
  • 结果

请求参数 username 的值为: hanzong

postformvalue 方法

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

  • 代码
func handler(w http.responsewriter, r *http.request) {
//获取请求参数
fmt.fprintln(w, "请求参数 username 的值为:", r.postformvalue("username"))
}
  • 结果
  • 请求参数 username 的值为: hanzong

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>

1) 后台处理请求代码

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))
}
}
}

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))
}
}
}