HTTP 请求
1.Request请求
2.URL
3. Header
4.Body
HTTP Request 和 HTTP Response(请求和响应)
他们具有相同的结构:
请求(响应)行
0个或者多个Header
空行
可选的消息体(Body)
Request (是个struct) 代表了客户端发送得 HTTP 请求消息
重要字段:URL Header Body Form PostForm MultiparForm
也可以通过Request 的方法访问请求的 Cookie URL User Agent 等信息
Request 即可代表服务器请求,又可以代表客户端发送的请求。
Request 的URL 字段代表请求行(请求信息第一行) 里边的部分内容
URL字段是指向 url.URL类型的一个指针, url.URL 是一个结构体
URL的通用形式: scheme://[userinfo@]host/path[?query][#fragment]
不可以斜杠开头的 URL会被解释成 : scheme:opaque[?query][#fragment]
URL Query 会提供实际查询的字符串
例如:HTTP://www.example.com/post?id=123&thread_id=456
URL Fragment 详细信息
如果从浏览器发出的请求,那么你无法提取出Fragment 字段值。(鸡肋现在没啥卵用)
Request Header
请求和响应(Request Response) 的 Header是通过 类型来描述,他是一个map,用来表述HTTP Header 里的Key-value对
Header Map 的Key是string类型 Value是[]string 切片
设置key 的时候就会创建一个空的[]string 作为 value ,其中的第一个值就是新的header值。
为指定key添加一个新的header 值,执行append操作即可。
Request Header 例子
1 r.header 返回map
2 r.Header[“key”] 返回[]string 切片
3 r.Header.Get(key) 返回时string 结果集用 逗号 隔开
Request Body
请求和响应的bodies 都是使用Body 字段来表示
Body是一个io.ReadCloser接口
一个Reader接口
一个Closer接口
Reader 接口定义了一个Open 方法
参数:[]byte
返回: byte的数量,可选错误
Closer 接口定义了一个Close方法
没有参数,返回值可选的错误。
4.1 查询参数(Query Parameters)
URL Query: 例如:HTTP://www.example.com/post?id=123&thread_id=456
r.URL.RawQuery 会提供实际查询的原始字符串
上面的例子得到的数值: id=123&thread_id=456
r.URL.Query() 会提供查询字符串对应的map[string] []string
4.2 通过表单发送请求
Form 字段
简单文本: 表单URL编码
大量数据,例如上传文件:multipart-mime
甚至可以把二进制数据通过Base64 编码,当做文本进行发送
表单Get请求没有Body 所有数据都是通过URL 的name-value 对发送
Request 上的函数准许我们从URL或者 Body 中提取数据,通过这些字段
Form
PostForm
MultipartForm
Form 里边的数据是key-value 对
通常的做法是:
先调用ParseForm或者ParseMultipartForm来解析Request
然后在响应的访问Form PostForm MultipartForm
PostForm字段
只取表单里边的数据,忽略url里边请求的信息。
以上的两个字段都可以使用r.ParseForm() 进行数据解析,解析表单应该是这种类型enctype="application/x-www-form-urlencoded" 如果是其他类型应当慎重解析
MultipartForm 字段
对应表单的提交方式应该为: enctype=“multipart/form-data” 解析方式应该对应为:r.ParseMultipartForm(r.ContentLength)
第二个参数是数据长度。
MultipartForm 只包含表单的key-value
返回类型是一个struct 而不是map 这个struct有两个map
FormValue 和PostFormValue 方法
FormValue 方法会返回Form 字段中指定Key 对应的第一个value
无需先调用ParseForm 或者ParseMultipartForm
PostFormValue 方法也是一样,但只能调取PostForm
但是如果表单enctype 设置为 Multipart / form-data 那么即使你调用PostFormValue获得想要的值
文件(Files)
上传文件:Multipart/form-data 常见的应用场景就是长传文件(例子)
首先调用ParseMultipartForm 方法
从File字段 获得FileHeader ,调用其Open方法获取文件
可以使用ioutil.ReadAll 函数把文件内容读取到byte 切片里
如果调用 FormFile 方法可以不用先不用调用 r.ParseMultipartForm(r.ContentLength)
file,_,err := r.FormFile(key值)
例子;
package main
import (
“fmt”
“io/ioutil”
“net/http”
)
func main() {
http.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(r.ContentLength)
fileHeader := r.MultipartForm.File[“upload”][0]
file, err := fileHeader.Open()
if err == nil {
data, err := ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(rw, string(data))
}
}
fmt.Fprintln(rw, r.MultipartForm)
})
http.ListenAndServe(":8081", nil)
//http.ListenAndServe(":8081", http.FileServer(http.Dir("www4399")))
}
网页示例:
Post JSON
不是所有的POST 请求都来自From
客户端框架(例如:Angular等) 会以不同的方式对Post请求解码;
jQuery 通常使用 application/x-www-form-urlencoded
Angular 是Application/json
ParseForm 方法无法处理 application/json
5.1 Form-MultipartReader()
方法签名:func(r *Request) MultipartReader()(*multipart.Reader ,error)
如果是 Multipart/form-data 或 Multipart 混合的post请求
否则返回nil 和一个错误
可以使用该函数代替ParseMultipartForm 来吧请求的Body 作为 Stream 进行处理
它不是把表单作为一个对象来处理,不是一次性获得整个map
逐个检查来自表单的值,然后每次处理一个。
- ResponseWrite
从服务器向客户端返回响应需求要使用ResponseWriter
ResponseWrite 是一个接口,handler用他来返回响应
真正支撑ResponseWrite 的幕后Struct 是非导出的http.response
一个有趣的问题
为什么Handler 的ServerHTTP(rw ResponseWrite ,r *Request),只有一个指针类型?而rw是按值传递
答:实际rw实际也是指针类型,也是引用传递
写入到ResponseWrite
Write 方法接收一个byte 切片作为参数 然后把它写到HTTP 响应的Body 里面
如果在Write 方法被调用时, header 里边没有用设定content type ,那么数据前512 字节就会被用来检测 content type
例子:
package main
import (
“net/http”
)
func writeExple(rw http.ResponseWriter, r *http.Request) {
str := “
新年好啊!!!
”rw.Write([]byte(str))
}
func main() {
server := http.Server{
Addr: “localhost:8081”,
}
http.HandleFunc("/write", writeExple)
server.ListenAndServe()
}
WriteHeader 方法
WriteHeader 方法接收一个整数类型(HTTP 状态码) 作为参数,并把它作为HTTP 响应的状态码返回
如果该方法没有显示调用,那么在第一次调用Write 方法前,会隐士的调用WriteHeader(http.StatusOK)
所以WriteHeader 主要用来发送错误类型的HTTP状态码
调用完WriteHeader 方法后,仍然可以写入到ResponseWrite
但是无法在修改header了
例子:
package main
import (
“encoding/json”
“fmt”
“net/http”
)
func writeExple(rw http.ResponseWriter, r *http.Request) {
str := “
新年好啊!!!
”rw.Write([]byte(str))
}
func writeHeadExample(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(501)
fmt.Fprintln(rw, “不作死就不会死!no 咗 no 待”)
}
func headExample(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set(“Location”, “http://baidu.com”)
rw.WriteHeader(302)
}
func jsonExample(rw http.ResponseWriter, r *http.Request) {
rw.Header().Set(“Content-Type”, “application/json”)
data := &myData{
User: “王天发”,
Threads: []string{“你是谁”, “你爸爸”, “马飞飞”},
}
rJsonBts, _ := json.Marshal(data)
rw.Write(rJsonBts)
}
type myData struct {
User string
Threads []string
}
func main() {
server := http.Server{
Addr: “localhost:8081”,
}
http.HandleFunc("/write", writeExple)
http.HandleFunc("/writeHead", writeHeadExample)
http.HandleFunc("/headSet", headExample)
http.HandleFunc("/json", jsonExample)
server.ListenAndServe()
}
内置 Response
NotFound 函数,包装一个404 状态码和一个额外的信息
ServerFile 函数,从文件系统提供文件,返回给请求者
ServerContent 函数,他可以把是实现了io.ReadSeeker 接口的任何东西里边的内容返回给请求者
还可以处理Range请求(范围请求) 如果只请求了资源的一部分内容,那么ServeContent 就可以如此响应,而 ServerFile 或io.Copy则都不行
Redirect 函数,告诉客户端重定向另外一个URL
——————————————————————————————————————————————
模板部分主要内容
简介
Web模板就是先设计好的HTML 页面,他可以被模板引擎反复的使用,来产生HTML页面
Go的标准库提供了 text/template html/template 两个模板库
大多数Go的Web框架都使用这些库作为默认模板引擎
模板引擎
可以合并模板与上下文数据,最终的HTML
两种理想模板引擎
无逻辑模板引擎:通过占位符,动态数据被替换到模板中。不做任何逻辑处理,只做字符串替换,处理完全由handler来完成。目标是展示层和逻辑的完全分离。
逻辑嵌入模板引擎:编程语言被嵌入到模块中,在运行时由模板引擎来执行,包含替换功能,功能强大,逻辑代码遍布handle和模板 难以维护。
Go的模板引擎
主要用的是 text/template , HTML 相关部分使用了 html/template 是个混合体
模板可以完全无逻辑,但是又具有足够的嵌入特性。
和大多数模板引擎一样,Go Web的模块位于无逻辑和嵌入之前的某个地方。
Go的模板引擎工作原理
在web应用中,通过是由handler来触发模板引擎
handler 调用模板引擎,并将使用的模板传递给引擎(通常是一组模板文件和动态数据)
模板引擎生成HTML,并将其写入到ResponseWrite
ResponseWriter 再将它加入到HTTP 响应中,返回给客户端
关于模板
模板必须是可读文本格式,扩展名任意,对于Web 应用通常是HTML
里边会嵌入一些命令(叫做action)
text/template 是通用模板引擎, html/template 是HTML模板引擎
action 位于双层花括号之间: {{.}}
这里的. 就是一个action
使用模板引擎
解析模板源(可以是字符串或模板文件),从而创建一个解析好的模块的 struct
执行解析好的模板,并传入ResponseWriter 和数据
这会触发模板引擎组合解析好的模板和数据,来产生最终的HTML 并将它传递给ResponseWriter
例子:
func processExample(rw http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("index.html")
t.Execute(rw, "Hello 你好啊 (*´▽`)ノノ")
}
Action
参数,变量,管道
函数
模板组合
解析模板
ParseFile
解析模板文件,并创建一个解析好的模板 struct 后续可以被执行
ParseFile 函数是Template struct上ParseFiles 方法的简单调用
调用ParseFiles后,会创建一个新的模板,模板名字是文件名
New 函数
ParseFiles 的参数数量可变,但只返回一个模板
当解析多个文件时,第一个文件作为返回的模板(名,内容),其余的作为map 供后持续执行使用
ParseGlob
使用模式匹配来解析特定的文件
Parse
Must函数
可以包裹一个函数,返回到一个模板的指针 和一个错误
如果错误不为 nil 那么就panic
执行模板
Execute:参数是 ResponseWrite 数据。 单模板:很实用。 模板集: 只用第一个模板
ExecuteTemplate: 参数: ResponseWriter 模板名 数据。 模板集: 很适用