前言
Golang个人总结的Web部分由本人跟学教材时的个人理解与做题总结而来,难免具有很多错误,如发现请指正,谢谢!
本文题为个人总结,实则叫每日总结比较合适,目前记录为按每天来记录总结,待学习完后可能会重构为结构性更强的个人总结
电脑端可以于左栏“文章目录”来索引到指定小节,手机端可以通过左上角按钮唤出菜单索引到指定小节
正文
Day01-HelloWorld和处理Handle
HelloWorld
声明一个http.Server结构体类型的变量,其中结构体中Addr字段代表地址,:8080则会默认监听localhost:8080端口,第二个是参数是一个Handle类型,填写nil可以调用DefaultServeMux,是一个默认的多路复用器,然后编写函数体内的内容,最后调用监听并服务方法,自定义一个Handle的方法是通过声明一个结构体,然后实现Handler接口的方法,是一个名为ServeHTTP的方法,接受两个参数,第一个参数是类型为http.ResponseWrite的参数,第二个参数是一个类型为http.Request的指针,例:
package main
import(
net/http
)
//自定义Handler
type HelloHandle{}
//实现Handler接口中的ServeHTTP方法
func (HelloHandle)ServeHTTP(w http.ResponsWriter, r *http.Request){
//函数体内为处理请求的方法
w.Write([]byte("Hello World"))
}
func main (){
s := http.Server("localhost:8080",nil)//调用DefaultServeMux
http.Handle("/Hello",HelloHandle{})
s.ListenAndServe()//开始服务
}
依次,就实现了将自定义Handler注册到DefaultServeMux并且访问localhost:8080/hello就会得到Hello World
Day02
概括
内容有内置的五个Handler,请求(Request),Form以及其方法,ResponseWriter
内置的Handler
- http.NotFoundHandler
- 函数签名:
func NotFoundHandler() Handler
- 功能: 对于任何请求,都返回404 page not found。
- http.RedirectHandler
- 函数签名:
func RedirectHandler(url string, code int) Handler
- 功能: 重定向Handler,
url
指要跳转的链接,code
表示跳转的状态码(3xx)。
- http.StripPrefix
- 函数签名:
func StripPrefix(prefix string, h Handler) Handler
- 功能: 修饰Handler,意为“剥除前缀”,去除掉第一个参数内的前缀后调用第二个参数中的handler。如果提供的URL与前缀不符,则会返回404。
prefix
即为前缀,剥除前缀之后将剥除后的URL调用第二个参数的handler。
- http.TimeoutHandler
- 函数签名:
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler
- 功能: 修饰Handler,第一个传入的参数是调用(修饰)的Handler,第二个参数是指定的运行时间(单位是时间),第三个是在指定的运行时间内没有处理完返回的超时消息。
- http.FileServer
- 函数签名:
func FileServer(root FileSystem) Handler
- 功能: 返回一个Handler,使用基于
root
的文件系统来处理请求,其中,FileSystem
是一个接口。 - 接口定义:
type FileSystem interface { Open(name string) (File, error) }
- 常用实现:
http.Dir("文件路径")
func (d Dir)Open(name string)(File, error)
请求(Request)
HTTP消息分为两种,HTTP Request和HTTP Response(请求和响应)
他们具有相同的结构:
- 请求行
- 0个或多个Header
- 空行
- 可选的消息体(Body)
在net/http包中提供了用于表示http消息结构的东西,其中用来表示请求的就叫做Request,Request是一个结构体,代表了客户端发送的HTTP消息信息,在Request的字段中,有几个重要的字段:
- URL
- Header
- Body
- Form、PostForm、MultipartForm
通过Request内方法还可以访问其中的Cookie、URL、User Agent等信息,Request可以代表发送到服务器等请求,也可以代表客户端发送的请求
URL
URL字段代表了请求中的请求行的部分内容(不包含最前面的http方法和后面的http版本),其字段是指向url.URL的一个指针,url.URL是一个struct
URL的通用格式为:
//方括号内为可选项
scheme://[userinfo@]host/path[?query][#fragment]
URL的查询字符串
URL的查询字符串 (URL Query)
- RawQuery
- 功能: 提供实际查询的字符串。
- 示例:
- URL:
http://www.luckyqu.cn/post?id=123&thread_id=456
RawQuery
的值:id=123&thread_id=456
- URL:
- URL Fragment
- 功能: 如果是从浏览器发出的请求,那么Fragment无法被提取,因为浏览器在发送请求的时候会去掉fragment部分。
Header
- 概述
- 功能: HTTP消息的header是通过
Header
类型来描述的,它是一个map,用来表示HTTP Header中的Key-Value对。 - 类型:
map[string][]string
key
的值为string
,value
是[]string
类型。
- 设置Header
- 创建新的key:
- 在设置key的时候会创建一个空的
[]string
作为value,value里面的第一个元素就是header的值。
- 在设置key的时候会创建一个空的
- 添加新的value:
- 为指定的key添加一个新的value执行
append
操作即可。
- 为指定的key添加一个新的value执行
- 获取Header
- 获取全部:
- 使用
r.Header
字段获取全部,返回一个map。
- 使用
- 获取特定key的value:
- 使用
r.Header["Accept-Encoding"]
获取给定key的一个value,返回值是[gzip, deflate]
([]string
类型)。
- 使用
- 获取特定key的第一个value:
- 使用
r.Header.Get("Accept-Encoding")
返回gzip, deflate
(字符串类型,多个值用逗号隔开)。
- 使用
请求的Body
- 概述
- 功能: 请求和响应都是使用
Body
字段来表示Body的。 - 类型:
io.ReadCloser
接口- 实现了
io.Reader
和io.Closer
接口。
- 实现了
- 接口方法
- Reader接口:
Read(p []byte) (n int, err error)
: 读取数据到p
中,返回读取的字节数和可选的错误。
- Closer接口:
Close() error
: 关闭资源,返回可选的错误。
- 读取Body内容
- 方法: 使用
Body
的Read
方法读取内容。 - 获取长度: 使用
r.ContentLength
获取Body的长度。
URL.Query
- 概述
- 功能: 查询参数(Query)。
- 方法:
r.URL.Query()
会返回查询字符串对应的map[string][]string
。
- 获取特定key的value
- 方法:
r.URL.Query().Get(key)
会返回传入key对应的第一个value。
Form
前置知识
- 通过表单发送请求
- 示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Form Test</title>
</head>
<body>
<form action="/File" method="post" enctype="application/x-www-form-urlencoded">
<label>
<input type="text" name="first_name"/>
</label>
<label>
<input type="text" name="last_name"/>
</label>
<input type="submit"/>
</form>
</body>
</html>
- 解释:
action
属性对应处理的路径。method
属性后跟post
表示这是一个POST请求。input
表示输入块,type="text"
表示文本输入,type="submit"
表示提交按钮。
- 表单数据的发送
- 数据格式:
- 表单内的数据会以name-value对的形式,通过POST请求发送出去,数据内容在POST请求的Body里面。
- Content-Type:
- 通过表单的
enctype
属性来指定,enctype
的默认值为application/x-www-form-urlencoded
。 - 浏览器至少要求支持
application/x-www-form-urlencoded
和multipart/form-data
(HTML5需额外支持text/plain
)。
- 通过表单的
- 不同的Content-Type
- application/x-www-form-urlencoded:
- 浏览器会将表单数据编码到查询字符串内,与URL一同发送给服务器。
- 例如,点击提交后发送的就是:
first_name=sau%20sheong&last_name=chang
- multipart/form-data:
- 每一个name-value会被转换为一个MIME消息部分,每一个部分都有自己的
Content-Type
和Content-Disposition
。 - 例如:
Content-Disposition: form-data; name="first_name" sau sheong Content-Disposition: form-data; name="last_name" chang
- 每一个name-value会被转换为一个MIME消息部分,每一个部分都有自己的
- 选择合适的Content-Type:
- 当数据为简单文本时,使用表单URL编码(
application/x-www-form-urlencoded
)。 - 当有大量数据时,例如上传文件,使用多部分MIME形式(
multipart/form-data
)。
- 表单的method属性:
- 通过表单的
method
属性可以设置POST还是GET。 - GET请求没有Body,所有的数据都通过URL的name-value对来发送。
正文
- Request上的函数
- Form:
Form
字段包含所有表单和URL参数。
- PostForm:
PostForm
字段仅包含POST表单数据。
- MultipartForm:
MultipartForm
字段用于处理multipart/form-data
。
- 解析表单数据
- 通常做法:
- 先调用
ParseForm
或ParseMultipartForm
来解析请求。 - 然后再相应地访问
Form
、PostForm
或MultipartForm
字段。
- 先调用
- PostForm字段
- 获取特定值:
- 例如,如果只想得到
first_name
这个key对应的value,可以使用r.Form["first_name"]
,它返回一个包含一个元素的slice:["Dave"]
。
- 例如,如果只想得到
- 处理重复键:
- 如果表单和URL里有同样的key,那么它们都会放在一个slice里,表单里的值靠前,URL里的值靠后。
- 仅获取表单数据:
- 如果只想要表单的key-value对,不要URL的,可以使用
PostForm
字段。
- 如果只想要表单的key-value对,不要URL的,可以使用
- 限制:
PostForm
只支持application/x-www-form-urlencoded
。
- MultipartForm字段
- 使用方法:
- 想要使用
MultipartForm
字段,首先必须调用ParseMultipartForm
方法。 - 这个方法会在必要的时候自动调用
ParseForm
方法。 - 参数是需要读取数据的最大长度(字节数)。
- 想要使用
- 返回类型:
MultipartForm
只包含表单的key-value对。- 返回类型是一个struct,而不是map,这个struct中有两个map:
- 第一个map的key是string,value是
[]string
。 - 第二个map的key是string,value是文件。
- FormValue和PostFormValue
- FormValue:
- 返回
Form
字段中指定Key对应的第一个value,无需调用ParseForm
或ParseMultipartForm
。
- 返回
- PostFormValue:
- 返回
PostForm
字段中指定Key对应的第一个value,仅限于POST表单数据。
- 返回
- 注意事项:
- 以上两个方法都会调用
ParseMultipartForm
方法,但如果表单的enctype
设置为multipart/form-data
,调用ParseMultipartForm
方法后无法通过FormValue
获得想要的值。
- 以上两个方法都会调用
- 上传文件
- 常规方法:
- 首先调用
ParseMultipartForm
方法,从File
字段中获得FileHeader
,调用其Open
方法来获得文件,可以使用ioutil.ReadAll
函数把文件内容读取到byte切片中。
- 首先调用
- 简便方法:
- 使用
FormFile
方法,无需调用ParseMultipartForm
方法。 - 返回指定key对应的第一个value,同时返回
File
和FileHeader
,以及错误信息。 - 面对只上传一个文件的形式,这种方式会更快。
- 使用
- 处理非表单的POST请求
- 限制:
- 不是所有的POST请求都来自于表单,
ParseForm
无法处理application/json
。
- 不是所有的POST请求都来自于表单,
- MultipartReader
- 函数签名:
func (r *Request) MultipartReader() (*multipart.Reader, error)
- 功能:
- 如果是
multipart/form-data
或multipart
混合的POST请求,返回一个MIME multipart reader。 - 否则返回
nil
和一个错误。
- 如果是
- 用途:
- 可以使用该函数代替
ParseMultipartForm
来把请求的body作为stream进行处理。 - 不是把表单作为一个对象处理,也不是一次性获得整个map,而是逐个检查来自表单的值,然后每次处理一个。
- 可以使用该函数代替
ResponseWriter&内置的Response
ResponseWriter
- 概述
- 用途: 从服务器向客户端返回响应需要使用
ResponseWriter
。 - 类型:
ResponseWriter
是一个接口,handler用它来返回响应。 - 底层结构: 真正支撑
ResponseWriter
的背后结构是非导出的http.response
。 - 传递方式:
ResponseWriter
本质上也是一个指针,所以是按引用传递。
- 方法
- Write
- 签名:
Write([]byte) (int, error)
- 功能: 接收一个byte切片作为参数,然后将它写入到HTTP响应的Body里面。
- Content-Type检测: 如果在
Write
方法被调用时,header里面没有设定Content-Type
,那么数据的前512字节会被用来检测Content-Type
。
- 签名:
- WriteHeader
- 签名:
WriteHeader(int)
- 功能: 接收一个整数类型(HTTP状态码)作为参数,并把它作为HTTP响应的状态码返回。
- 隐式调用: 如果该方法没有显式调用,那么在第一次调用
Write
方法前,会隐式调用WriteHeader(http.StatusOK)
。 - 用途: 主要用来发送错误类的HTTP状态码。
- 限制: 调用完
WriteHeader
方法之后,仍然可以写入到ResponseWriter
,但无法再修改header。
- 签名:
- Header
- 签名:
Header() http.Header
- 功能: 返回headers的map,可以进行修改。
- 效果: 修改后的headers将会体现在返回给客户端的HTTP响应里。
- 签名:
内置的 Response
- NotFound
- 函数签名:
func NotFound(w ResponseWriter, r *Request)
- 功能: 包装一个404状态码和一个额外的信息,返回给客户端。
- ServeFile
- 函数签名:
func ServeFile(w ResponseWriter, r *Request, name string)
- 功能: 从文件系统提供文件,返回给请求者。
- ServeContent
- 函数签名:
func ServeContent(w ResponseWriter, r *Request, name string, modtime time.Time, content io.ReadSeeker)
- 功能:
- 从文件系统提供文件,返回给请求者。
- 可以处理Range请求(范围请求),如果只请求了资源的一部分内容,那么
ServeContent
可以如此响应,而ServeFile
或者io.Copy
则不行。
- Redirect
- 函数签名:
func Redirect(w ResponseWriter, r *Request, url string, code int)
- 功能: 告诉客户端重定向到另一个URL。