Request结构
Request结构主要由以下部分组成
URL字段
Header字段
Body字段
Form字段、PostForm字段和MultipartForm字段
[HTML] 纯文本查看 复制代码
type Request struct {
Method string
URL *url.URL
Proto string // "HTTP/1.0"
ProtoMajor int // 1
ProtoMinor int // 0
Header Header
Body io.ReadCloser
GetBody func() (io.ReadCloser, error)
ContentLength int64
TransferEncoding []string
Close bool
Host string
Form url.Values
PostForm url.Values
MultipartForm *multipart.Form
Trailer Header
RemoteAddr string
RequestURI string
TLS *tls.ConnectionState
Cancel <-chan struct{}
Response *Response
ctx context.Context
}
请求URL
Request结构中的URL字段用于表示请求行中包含的URL
[JavaScript] 纯文本查看 复制代码 type URL struct {
Scheme string
Opaque string // encoded opaque data
User *Userinfo // username and password information
Host string // host or host:port
Path string // path (relative paths may omit leading slash)
RawPath string // encoded path hint (see EscapedPath method)
ForceQuery bool // append a query ('?') even if RawQuery is empty
RawQuery string // encoded query values, without '?'
Fragment string // fragment for references, without '#'
}
URL的一般格式:[scheme:][//[userinfo@]host][/]path[?query][#fragment]
客户端通过URL的查询参数向服务器传递信息,而URL结构的RawQuery字段记录的就是客户端向服务器传递的查询参数字符串。如:http://www.example.com/post?id=1234&name=chen ,则RawQuery字段的值存储的就是id=1234&name=chen ,要想获取键值对格式的查询参数,要对RawQuery值进行语法分析,但是使用Request结构的Form字段,系统提供了解析RawQuery的方法,将解析的键值对信息会存储在Form字段中。下面会主要会对Request结构的Form字段、PostForm字段和MultipartForm字段进行讲解。
请求首部
http.Header类型拥有4中基本方法,这些方法根据给定的键执行添加、删除、获取和设置等操作。
[JavaScript] 纯文本查看 复制代码
import (
"net/http"
"fmt"
)
func headers(w http.ResponseWriter,r *http.Request) {
r.ParseForm()
h := r.Header
fmt.Println(r.Header.Get("Accept-Encoding")) //gzip, deflate
fmt.Println(r.Header["Accept-Encoding"]) //[gzip, deflate]
fmt.Fprintln(w,h)
}
func main() {
http.HandleFunc("/headers",headers)
http.ListenAndServe(":8080",nil)
}
r.Header.Get("Accept-Encoding")是通过Header类型的Get方法获取的头信息,其返回的就是字符串形式的首部值,而r.Header["Accept-Encoding"]是以切片的形式返回的。
请求主体
请求和响应的主体都是由Request结构的Body字段表示,该字段是一个io.ReadCloser接口。
[JavaScript] 纯文本查看 复制代码
import (
"net/http"
"fmt"
)
func body(w http.ResponseWriter,r *http.Request) {
bys := make([]byte,r.ContentLength)
r.Body.Read(bys)
w.Write(bys)
}
func main() {
http.HandleFunc("/body",body)
http.ListenAndServe(":8080",nil)
}
通过ContentLength表示的是主体数据的字节长度,根据该长度创建字节切片,在通过Read方法将主体数据读取到字节切片中。因为GET请求不包含报文主体,所以使用的是POST表单请求。
Go语言提供了诸如FormValue和FormFile这种的方法来提取通过POST方法提交的表单,所以用户一般不需要自行读取主体中未经处理的表单,以下讲解FormValue和FormFile等方法。
Go与HTML表单
HTML表单的内容类型(Content-Type)决定了POST请求在发送键值对时将使用何种格式,其中,表单的enctype(也就是Content-Type)属性指定的值可以是application/x-www-form-urlencoded和multipart/form-data等。如果enctype属性的值设置为application/x-www-form-urlencoded,那么表单中的数据编码为一个连续的“长查询字符串”,这种编码和URL编码是一样的,如:id=1234&name=chen。如enctype属性的值设置为multipart/form-data,那么表单中的数据将被转换为一条MIME报文,表单中的每个键值对都构成了这条报文的一部分,并且每个键值对都带有它们各自的内容类型以及内容配置。以下是使用multipart/form-data编码对表单数据进行格式化的例子:
----------------------------780741602912379251409253
Content-Disposition: form-data; name="id"
123
----------------------------780741602912379251409253
Content-Disposition: form-data; name="name"
chen
----------------------------780741602912379251409253--
那么application/x-www-form-urlencoded和multipart/form-data两种编码应该如何选择呢,如果表单传送的简单的文本数据,那么使用URL编码格式更好,因为这种编码更为简单、高效,并且它所需的计算量要比另一种编码少,如果表单需要传送大量数据(如上传文件),那么使用multipart/form-data编码格式会更好一些。
Form字段
前面提到了如果直接获取请求体数据,需要自行进行语法分析,解析出键值对数据,而net/http库已经提供了一套用途相当广泛的函数,这些函数一般都能够满足用户对数据提取方面的需求,所以我们很少需要自行对表单数据进行语法分析。
通过调用Request结构提供的方法,用户可以将URL、主体又或者以上两者记录的数据提取到该结构的Form、PostForm和MultipartForm等字段当中。跟我们平常通过POST请求获取到的数据一样,存储在这些字段里面的数据也是以键值对形式表示的。使用Request结构的方法获取表单数据的一般步骤是:
(1)调用ParseForm()方法或者ParseMultipartForm()方法,对请求进行语法分析。
(2)根据步骤1调用的方法,访问相应的Form字段、PostForm字段或MultipartForm字段。
使用ParseForm()方法对表单进行语法分析的例子:
[JavaScript] 纯文本查看 复制代码 import (
"net/http"
"fmt"
)
func process(w http.ResponseWriter,r *http.Request) {
fmt.Println(r.Form) //map[]
r.ParseForm()
fmt.Println(r.Form) //map[id:[123] name:[chen hello world] hello:[world]]
fmt.Fprint(w,r.Form)
}
func main() {
http.HandleFunc("/process",process)
http.ListenAndServe(":8080",nil)
}
|