概述
前面我们学习了处理器和处理器函数,如何编写和注册处理器。本文我们将学习如何从请求中获取信息。
请求的结构
通过前面的学习,我们知道处理器函数需要符合下面的签名:
func (w http.ResponseWriter, r *http.Request)
其中,http.Request
就是请求的类型。客户端传递的数据都可以通过这个结构来获取。结构Request
定义在包 net/http 中:
// src/net/http/request.go
type Request struct {
Method string
URL *url.URL
Proto string
ProtoMajor int
ProtoMinor int
Header Header
Body io.ReadCloser
ContentLength int
// 省略一些字段...
}
我们来看一下几个重要的字段。
Method
请求中的Method
字段表示客户端想要调用服务器的哪个方法。在第一篇文章中,我们提到过 HTTP 协议方法。其取值有GET/POST/PUT/DELETE
等。服务器根据请求方法的不同会进行不同的处理,例如GET
方法只是获取信息(用户基本信息,商品信息等),POST
方法创建新的资源(注册新用户,上架新商品等)。
URL
Tim Berners-Lee 在创建万维网的同时,也引入了使用字符串来表示互联网资源的概念。他称该字符串为统一资源标识符(URI,Uniform Resource Identifier)。URI 由两部分组成。一部分表示资源的名称,即统一资源名称(URN,Uniform Resource Name)。另一部分表示资源的位置,即统一资源定位符(URL,Uniform Resource Location)。
在 HTTP 请求中,使用 URL 来对要操作的资源位置进行描述。URL 的一般格式为:
[scheme:][//[userinfo@]host][/]path[?query][#fragment]
scheme
:协议名,常见的有httphttpsftp
;userInfo
:若有,则表示用户信息,如用户名和密码可写作dj:password
;host
:表示主机域名或地址,和一个可选的端口信息。若端口未指定,则默认为 80。例如www.example.com
,www.example.com:8080
,127.0.0.1:8080
;path
:资源在主机上的路径,以/
分隔,如/posts
;query
:可选的查询字符串,客户端传输过来的键值对参数,键值直接用=
,多个键值对之间用&
连接,如page=1&count=10
;fragment
:片段,又叫锚点。表示一个页面中的位置信息。由浏览器发起的请求 URL 中,通常没有这部分信息。但是可以通过ajax
等代码的方式发送这个数据;
我们来看一个完整的 URL:
http://dj:password@www.example.com/posts?page=1&count=10#fmt
Go 中的 URL 结构定义在net/url
包中:
// net/url/url.go
type URL struct {
Scheme string
Opaque string
User *Userinfo
Host string
Path string
RawPath string
RawQuery string
Fragment string
}
可以通过请求对象中的URL
字段获取这些信息。接下来,我们编写一个程序来具体看看(使用上一篇文章讲的 Web 程序基本结构,只需要增加处理器函数和注册即可):
func urlHandler(w http.ResponseWriter, r *http.Request) {
URL := r.URL
fmt.Fprintf(w, "Scheme: %s\n", URL.Scheme)
fmt.Fprintf(w, "Host: %s\n", URL.Host)
fmt.Fprintf(w, "Path: %s\n", URL.Path)
fmt.Fprintf(w, "RawPath: %s\n", URL.RawPath)
fmt.Fprintf(w, "RawQuery: %s\n", URL.RawQuery)
fmt.Fprintf(w, "Fragment: %s\n", URL.Fragment)
}
// 注册
mux.HandleFunc("/url", urlHandler)
运行服务器,通过浏览器访问localhost:8080/url/posts?page=1&count=10#main
:
Scheme:
Host:
Path: /url/posts
RawPath:
RawQuery: page=1&count=10
Fragment:
为什么会出现空字段?注意到源码Request
结构中URL
字段上有一段注释:
// URL specifies either the URI being requeste