您现在的位置是:网站首页> 编程资料编程资料
Go语言使用Request,Response处理web页面请求_Golang_
2023-05-26
411人已围观
简介 Go语言使用Request,Response处理web页面请求_Golang_
Go语言处理web页面请求
Request和Response
http Requset和Response的内容包括以下几项:
- Request or response line
- Zero or more headers
- An empty line, followed by …
- … an optional message body
例如一个http Request:
GET /Protocols/rfc2616/rfc2616.html HTTP/1.1 Host: www.w3.org User-Agent: Mozilla/5.0 (empty line)
如果是POST方法,在empty line后还包含请求体。
一个http Response:
HTTP/1.1 200 OK Content-type: text/html Content-length: 24204 (empty line) and then 24,204 bytes of HTML code
go http包分为两种角色:http Client和http Server。http Client可以发送请求,比如写爬虫程序时语言扮演的角色就是http Client;http Server用来提供web服务,可以处理http请求并响应。

对于Request,作为http客户端(如编写爬虫类工具)常需要关注的是URL和User-Agent以及其它几个Header;作为http服务端(web服务端,处理请求)常需要关注的几项是:
URL Header Body Form,、PostForm、MultipartForm
以下是完整的Request结构以及相关的函数、方法:混个眼熟就好了
type Request struct { Method string URL *url.URL Header Header Body io.ReadCloser GetBody func() (io.ReadCloser, error) // Server: x, Cleint: √ ContentLength int64 TransferEncoding []string Close bool // Server: x, Cleint: √ Host string Form url.Values PostForm url.Values MultipartForm *multipart.Form Trailer Header RemoteAddr string RequestURI string // x TLS *tls.ConnectionState Cancel <-chan struct{} // x Response *Response // x } func NewRequest(method, url string, body io.Reader) (*Request, error) func ReadRequest(b *bufio.Reader) (*Request, error) func (r *Request) AddCookie(c *Cookie) func (r *Request) BasicAuth() (username, password string, ok bool) func (r *Request) Context() context.Context func (r *Request) Cookie(name string) (*Cookie, error) func (r *Request) Cookies() []*Cookie func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) func (r *Request) FormValue(key string) string func (r *Request) MultipartReader() (*multipart.Reader, error) func (r *Request) ParseForm() error func (r *Request) ParseMultipartForm(maxMemory int64) error func (r *Request) PostFormValue(key string) string func (r *Request) ProtoAtLeast(major, minor int) bool func (r *Request) Referer() string func (r *Request) SetBasicAuth(username, password string) func (r *Request) UserAgent() string func (r *Request) WithContext(ctx context.Context) *Request func (r *Request) Write(w io.Writer) error func (r *Request) WriteProxy(w io.Writer) error 注意有哪些字段和方法,字段的详细说明见go doc http.Request。上面打了"x"的表示不需要了解的或者废弃的。
有一个特殊的字段Trailer,它是Header类型的,显然它存放的是一个个请求header,它表示请求发送完成之后再发送的额外的header。对于Server来说,读取了request.Body之后才会读取Trailer。很少有浏览器支持HTTP Trailer功能。
以下是完整的Response结构以及相关的函数、方法:混个眼熟就好了
type Response struct { Status string // e.g. "200 OK" StatusCode int // e.g. 200 Proto string // e.g. "HTTP/1.0" ProtoMajor int // e.g. 1 ProtoMinor int // e.g. 0 Header Header Body io.ReadCloser ContentLength int64 TransferEncoding []string Close bool Uncompressed bool Trailer Header Request *Request TLS *tls.ConnectionState } func Get(url string) (resp *Response, err error) func Head(url string) (resp *Response, err error) func Post(url string, contentType string, body io.Reader) (resp *Response, err error) func PostForm(url string, data url.Values) (resp *Response, err error) func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) func (r *Response) Cookies() []*Cookie func (r *Response) Location() (*url.URL, error) func (r *Response) ProtoAtLeast(major, minor int) bool func (r *Response) Write(w io.Writer) error 其实有些直接从字面意思看就知道了。
Http Header
Request和Response结构中都有Header字段,Header是一个map结构。
type Header map[string][]string A Header represents the key-value pairs in an HTTP header. func (h Header) Add(key, value string) func (h Header) Del(key string) func (h Header) Get(key string) string func (h Header) Set(key, value string) func (h Header) Write(w io.Writer) error func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error
key是Header字段名,value是Header字段的值,同个字段多个值放在string的slice中。
Add()、Del()、Get()、Set()意义都很明确。
Write()是将Header写进Writer中,比如从网络连接中发送出去。WriteSubSet()和Write()类似,但可以指定exclude[headerkey]==true排除不写的字段。
下面是一个示例:
package main import ( "fmt" "net/http" ) func headers(w http.ResponseWriter, r *http.Request) { for key := range r.Header { fmt.Fprintf(w, "%s: %s\n", key, r.Header[key]) } fmt.Fprintf(w, "--------------\n") fmt.Fprintf(w, "the key: %s\n", r.Header["Accept-Encoding"]) fmt.Fprintf(w, "the key: %s\n", r.Header.Get("Accept-Encoding")) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/headers", headers) server.ListenAndServe() } 浏览器中访问http://127.0.0.1:8080/headers的结果:
Connection: [keep-alive] Cache-Control: [max-age=0] Upgrade-Insecure-Requests: [1] User-Agent: [Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 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;q=0.8] -------------- the key: [gzip, deflate, br] the key: gzip, deflate, br
Http Body
Request和Response结构中都有Body字段,它们都是io.ReadCloser接口类型。从名字可以看出,io.ReadCloser由两个接口组成:Reader和Closer,意味着它实现了Reader接口的Read()方法,也实现了Closer接口的Close()方法。这意味着Body的实例可以调用Read()方法,也可以调用Close()方法。
例如,下面写一个handler,从请求中读取Body并输出:
package main import ( "fmt" "net/http" ) func body(w http.ResponseWriter, r *http.Request) { len := r.ContentLength body := make([]byte, len) r.Body.Read(body) fmt.Fprintf(w, "%s\n", string(body)) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/body", body) server.ListenAndServe() } 因为使用HTTP Get方法的Request没有Body,所以这里使用curl的"-d"选项来构造一个POST请求,并发送Request Body:
$ curl -id "name=lognshuai&age=23" 127.0.0.1:8080/body HTTP/1.1 200 OK Date: Mon, 26 Nov 2018 09:04:40 GMT Content-Length: 22 Content-Type: text/plain; charset=utf-8 name=lognshuai&age=23
Go和HTML Form
在Request结构中,有3个和form有关的字段:
// Form字段包含了解析后的form数据,包括URL的query、POST/PUT提交的form数据 // 该字段只有在调用了ParseForm()之后才有数据 Form url.Values // PostForm字段不包含URL的query,只包括POST/PATCH/PUT提交的form数据 // 该字段只有在调用了ParseForm()之后才有数据 PostForm url.Values // Go 1.1 // MultipartForm字段包含multipart form的数据 // 该字段只有在调用了ParseMultipartForm()之后才有数据 MultipartForm *multipart.Form
所以,一般的逻辑是:
- 先调用ParseForm()或ParseMultipartForm()解析请求中的数据
- 按需访问Request结构中的Form、PostForm或MultipartForm字段
除了先解析再访问字段的方式,还可以直接使用Request的方法:
- FormValue(key)
- PostFormValue(key)
稍后解释这两个方法。
取Form和PostForm字段
给定一个html文件,这个html文件里是form表单:
Go Web
在这个form里,action指定了要访问的url,其中path=process,query包含name和boyfriend两个key。除此之外,form表单的input属性里,也定义了name和age两个key,由于method为post,这两个key是作为request body发送的,且因为enctype指定为application/x-www-form-urlencoded,这两个key会按照URL编码的格式进行组织。
下面是web handler的代码:
package main import ( "fmt" "net/http" ) func form(w http.ResponseWriter, r *http.Request) { r.ParseForm() fmt.Fprintf(w, "%s\n", r.Form) fmt.Fprintf(w, "%s\n", r.PostForm) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/process", form) server.ListenAndServe() } 上面先使用ParseForm()方法解析Form,再访问Request中的Form字段和PostForm字段。
打开前面的Html文件,点击"提交"后,将输出:
map[name:[longshuai xiaofang] age:[23] boyfriend:[longshuai]] map[name:[longshuai] age:[23]]
如果这时,将application/x-www-form-urlencoded改成multipart/form-data,再点击提交,将输出:
map[name:[xiaofang] boyfriend:[longshuai]] map[]
显然,使用multipart/form-data编码form的时候,编码的内容没有放进Form和PostForm字段中,或者说编码的结果没法放进这两个字段中。
取MultipartForm字段
要取MultipartForm字段的数据,先使用ParseMultipartForm()方法解析Form,解析时会读取所有数据,但需要指定保存在内存中的最大字节数,剩余的字节数会保存在临时磁盘文件中。
package main import ( "fmt" "net/http" ) func form(w http.ResponseWriter, r *http.Request) { r.ParseMultipartForm(1024) fmt.Fprintf(w,"%s\n",r.Form) fmt.Fprintf(w,"%s\n",r.PostForm) fmt.Fprintf(w,"%s\n",r.MultipartForm) } func main() { server := http.Server{ Addr: "127.0.0.1:8080", } http.HandleFunc("/process", form) server.ListenAndServe() } 将html文件的enctype改为multipart/form-data后,重新点开html文件,将输出:
map[name:[xiaofang longshuai] boyfriend:[longshuai] age:[23]] map[name:[longshuai] age:[23]] &{map[name:[longshuai] age:[23]] map[]} 前两行结果意味着ParseMultipartForm()方法也调用了ParseForm()方法,使得除了设置MultipartForm字段,也会设置Form字段和PostForm字段。
注意上面的第三行,返回的是一个struct,这个struct中有两个map,第一个map是来自form的key/value,第二个map为空,这个见后面的File。
最后还需注意的是,提示:
本文由神整理自网络,如有侵权请联系本站删除!
本站声明:
1、本站所有资源均来源于互联网,不保证100%完整、不提供任何技术支持;
2、本站所发布的文章以及附件仅限用于学习和研究目的;不得将用于商业或者非法用途;否则由此产生的法律后果,本站概不负责!
相关内容
- go语言beego框架jwt身份认证实现示例_Golang_
- Go语言读取,设置Cookie及设置cookie过期方法详解_Golang_
- 深入解析Go template模板使用详解_Golang_
- Go模板template用法详解_Golang_
- go语言beego框架分页器操作及接口频率限制示例_Golang_
- Go处理json数据方法详解(Marshal,UnMarshal)_Golang_
- Go基础教程系列之WaitGroup用法实例详解_Golang_
- GO语言协程互斥锁Mutex和读写锁RWMutex用法实例详解_Golang_
- Go实现线程池(工作池)的两种方式实例详解_Golang_
- go语言beego框架web开发语法笔记示例_Golang_
