對請求的處理
Go 語言的 net/http 包提供了一系列用于表示 HTTP 報文的結構,我們可以使用它
處理請求和發送相應,其中 Request 結構代表了客戶端發送的請求報文,下面讓我們看
一下 Request 結構體
獲取請求 URL
Request 結構中的 URL 欄位用于表示請求行中包含的 URL,改欄位是一個指向
url.URL 結構的指標
Path 欄位
-
獲取請求的 URL
-
例如:http://localhost:8080/hello?username=admin&password=123456
注: 通過 r.URL.Path 只能得到 /hello
RawQuery 欄位
-
獲取請求的 URL 后面?后面的查詢字串
-
例如:http://localhost:8080/hello?username=admin&password=123456
注: 通過 r.URL.RawQuery 得到的是 username=admin&password=123456
獲取請求頭中的資訊
通過 Request 結果中的 Header 欄位用來獲取請求頭中的所有資訊,Header 欄位
的型別是 Header 型別,而 Header 型別是一個 map[string][]string,string 型別的 key,
string 切片型別的值,
獲取請求頭中的所有資訊
-
r.Header
-
得到的結果如下:
map[User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36]
Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,ima
ge/apng,*/*;q=0.8] Accept-Encoding:[gzip, deflate, br] Accept-Language:[zh-
CN,zh;q=0.9,en-US;q=0.8,en;q=0.7] Connection:[keep-alive] Upgrade-Insecure-
Requests:[1]]
獲取請求頭中的某個具體屬性的值,如獲取 Accept-Encoding 的值
-
方式一:
r.Header[“Accept-Encoding”]- 得到的是一個字串切片
- 結果[gzip, deflate, br]
-
方式二:
r.Header.Get(“Accept-Encoding”)- 得到的是字串形式的值,多個值使用逗號分隔
- 結果 gzip, deflate, br
獲取請求體中的資訊
請求和回應的主體都是有 Request 結構中的 Body 欄位表示,這個欄位的型別是
io.ReadCloser 介面,該介面包含了 Reader 介面和 Closer 介面,Reader 介面擁有 Read
方法,Closer 介面擁有 Close 方法
通過指定 method=”post”來發送一個 POST 請求
由于 GET 請求沒有請求體,所以我們需要在 HTML 頁面中創建一個 form 表單,通
過指定 method=”post”來發送一個 POST 請求
- 表單
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<form
action="http://localhost:8080/getBody"
method="POST"
enctype="multipart/form-data"
>
用戶名:<input type="text" name="username" /><br />
密碼:<input type="password" name="password" /><br />
<input type="submit" />
</form>
</body>
</html>
- 服務器處理請求的代碼
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
//獲取內容的長度
length := r.ContentLength
//創建一個位元組切片
body := make([]byte, length)
//讀取請求體
r.Body.Read(body)
fmt.Fprintln(w, "請求體中的內容是:", string(body))
}
func main() {
http.HandleFunc("/getBody", handler)
http.ListenAndServe(":8080", nil)
}
-
在瀏覽器上顯示的結果
- 請求體中的內容是: username=hanzong&password=666666
獲取請求引數
下面我們就通過 net/http 庫中的 Request 結構的欄位以及方法獲取請求 URL 后面
的請求引數以及 form 表單中提交的請求引數
Form 欄位
- 型別是 url.Values 型別,Form 是決議好的表單資料,包括 URL 欄位的 query
引數和 POST 或 PUT 的表單資料, - Form 欄位只有在呼叫 Request 的 ParseForm 方法后才有效,在客戶端,會忽
略請求中的本欄位而使用 Body 替代 - 獲取表單中提交的請求引數(username 和 password)
- 代碼
func handler(w http.ResponseWriter, r *http.Request) {
//決議表單
r.ParseForm()
//獲取請求引數
fmt.Fprintln(w, "請求引數為:", r.Form)
}
//注意:在執行 r.Form 之前一定要呼叫 ParseForm 方法
//結果
//請求引數為: map[password:[666666] username:[hanzong]]
- d) 如果對 form 表單做一些修改,在 action 屬性的 URL 后面也添加相同的請求參
數,如下:
<form
action="http://localhost:8080/getBody?username=admin&pwd=123456"
method="POST"
>
用 戶 名 : <input type="text" name="username" value=https://www.cnblogs.com/ygjzs/p/"hanzong" />
密 碼 :
則執行結果如下:
請求引數為:map[username:[hanzong admin] password:[666666] pwd:[123456]]
- 我們發現:表單中的請求引數 username 和 URL 中的請求引數
username 都獲取到了,而且表單中的請求引數的值排在 URL 請求參
數值的前面 - 如果此時我們只想獲取表單中的請求引數該怎么辦呢?那就需要使
用 Request 結構中的 PostForm 欄位
PostForm 欄位
- 型別也是 url.Values 型別,用來獲取表單中的請求引數
- 將 r.Form 改為 r.PostForm 之后的代碼
func handler(w http.ResponseWriter, r *http.Request) {
//決議表單
r.ParseForm()
//獲取請求引數
fmt.Fprintln(w, "請求引數為:", r.PostForm)
}
- 結果
請求引數為:map[username:[hanzong] password:[666666]]
- 但是 PostForm 欄位只支持 application/x-www-form-urlencoded 編碼,如果
form 表單的 enctype 屬性值為 multipart/form-data,那么使用 PostForm 欄位
無法獲取表單中的資料,此時需要使用 MultipartForm 欄位
- 說明:form 表單的 enctype 屬性的默認值是 application/x-www-form-
urlencoded 編 碼 , 實 現 上 傳 文 件 時 需 要 講 該 屬 性 的 值 設 置 為
multipart/form-data 編碼格式
FormValue 方法和 e PostFormValue 方法
FormValue 方法
a) 可以通過 FormValue 方法快速地獲取某一個請求引數,該方法呼叫之前
會自動呼叫 ParseMultipartForm 和 ParseForm 方法對表單進行決議
- 代碼
func handler(w http.ResponseWriter, r *http.Request) {
//獲取請求引數
fmt.Fprintln(w, "請求引數username的值為:", r.FormValue("username"))
}
- 結果
請求引數 username 的值為: hanzong
PostFormValue 方法
a) 可以通過 PostFormValue 方法快速地獲取表單中的某一個請求引數,該
方法呼叫之前會自動呼叫 ParseMultipartForm 和 ParseForm 方法對表單
進行決議
- 代碼
func handler(w http.ResponseWriter, r *http.Request) {
//獲取請求引數
fmt.Fprintln(w, "請求引數 username 的值為:", r.PostFormValue("username"))
}
- 結果
請求引數 username 的值為: hanzong
MultipartForm 欄位
為了取得 multipart/form-data 編碼的表單資料,我們需要用到 Request 結構的
ParseMultipartForm 方法和 MultipartForm 欄位,我們通常上傳檔案時會將 form 表單的
enctype 屬性值設定為 multipart/form-data
- 表單
<form
action="http://localhost:8080/upload"
method="POST"
enctype="multipart/form-data"
>
用 戶 名 : <input type="text" name="username" value=https://www.cnblogs.com/ygjzs/p/"hanzong" />
檔案:
- 后臺處理請求代碼
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
//決議表單
r.ParseMultipartForm(1024)
fmt.Fprintln(w, r.MultipartForm)
}
func main() {
http.HandleFunc("/upload", handler)
http.ListenAndServe(":8080", nil)
}
- 瀏覽器顯示結果
&{map[username:[hanzong]] map[photo:[0xc042126000]]}
-
結果中有兩個映射,第一個映射映射的是用戶名;第二個映射的值是一個地址
-
MuiltipartForm 欄位的型別為 *multipart.Form,multipart 包下 Form 結構的指
針型別 -
打開上傳的檔案
func handler(w http.ResponseWriter, r *http.Request) {
//決議表單
r.ParseMultipartForm(1024)
fileHeader := r.MultipartForm.File["photo"][0]
file, err := fileHeader.Open()
if err == nil {
data, err := ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
FormFile 方法
-
net/http 提供的 FormFile 方法可以快速的獲取被上傳的檔案,但是只能處理上
傳一個檔案的情況, -
代碼
func handler(w http.ResponseWriter, r *http.Request) {
file, _, err := r.FormFile("photo")
if err == nil {
data, err := ioutil.ReadAll(file)
if err == nil {
fmt.Fprintln(w, string(data))
}
}
}
給客戶端回應
前面我們一直說的是如何使用處理器中的 *http.Request 處理用戶的請求,下面我
們來說一下如何使用 http.ResponseWriter 來給用戶回應
給客戶端回應一個字串
- 處理器中的代碼
func handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("你的請求我已經收到"))
}
- 瀏覽器中的結果
你的請求我已經收到 - 回應報文中的內容
HTTP/1.1 200 OK
Date: Fri, 10 Aug 2019 01:09:27 GMT
Content-Length: 27
Content-Type: text/plain; charset=utf-8
- 給客戶端回應一個 HTML 頁面
- 處理器中的代碼
func handler(w http.ResponseWriter, r \*http.Request) {
html := `<html>
<head>
<title>測驗回應內容為網頁</title>
<meta charset="utf-8"/>
</head>
<body>
我是以網頁的形式回應過來的!
</body>
</html>`
w.Write([]byte(html))
}
- 瀏覽器中的結果
我是以網頁的形式回應過來的!
- 通過在瀏覽器中右鍵 → 查看網頁代碼發現確實是一個 html 頁面
- 回應報文中的內容
HTTP/1.1 200 OK
Date: Fri, 10 Aug 2018 01:26:58 GMT
Content-Length: 194
Content-Type: text/html; charset=utf-8
-
給客戶端回應 JSON 格式的資料
-
處理器端代碼
func handler(w http.ResponseWriter, r \*http.Request) {
//設定回應頭中內容的型別
w.Header().Set("Content-Type", "application/json")
user := User{
ID: 1,
Username: "admin",
Password: "123456",
}
//將 user 轉換為 json 格式
json, \_ := json.Marshal(user)
w.Write(json)
}
- 瀏覽器中的結果
{"ID":1,"Username":"admin","Password":"123456"} - 回應報文中的內容
HTTP/1.1 200 OK
Content-Type: application/json
Date: Fri, 10 Aug 2018 01:58:02 GMT
Content-Length: 47
-
讓客戶端重定向
-
處理器端代碼
func handler(w http.ResponseWriter, r \*http.Request) {
//以下操作必須要在 WriteHeader 之前進行
w.Header().Set("Location", "https:www.baidu.com")
w.WriteHeader(302)
}
- 回應報文中的內容
HTTP/1.1 302 Found
Location: https:www.baidu.com
Date: Fri, 10 Aug 2018 01:45:04 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/55026.html
標籤:Go
