1. 程式人生 > 其它 >go web 學習第二天 筆記備忘

go web 學習第二天 筆記備忘

技術標籤:go langgohttp

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://[[email protected]]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
逐個檢查來自表單的值,然後每次處理一個。

  1. 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 模板名  資料。 模板集: 很適用