Go Web如何處理Web請求?

張君鴻發表於2019-03-27

Web應用程式最重要的功能,就是接收來自客戶端(一般是瀏覽器或APP)發起的請求,根據請求方法與型別返回靜態HTML頁面或動態生成客戶端想要的資料,而Go語言中net/http已經在處理請求資料方面做了很好的封裝,使得用Go程式碼處理Web請求的資料並生成響應資料變得非常簡單,下面一起學習一下吧!

Web請求

我們知道,一個HTTP事務由請求響應構成,這篇文章中,我們單講有關Web請求的部分。

客戶端一般是通過一個URL向伺服器發起請求,最簡單的比如在瀏覽位址列輸入:juejin.im

Go Web如何處理Web請求?

Chrome瀏覽器輸入掘鑫url

每一個Web請求都包括三個部分:請求行請求頭請求實體

請求方法

請求方法請求行當中,HTTP協議支援多種請求方法(method),主要有七種:

GET,POST,PUT,HEADER,PATCH,DELETE,OPTIONS

其中Web開發最常見就是GET方法和POST方法,使用GET方法發起的請求,沒有請求實體(body),因些請求的資料一般只能通過URL中的查詢引數(query)傳給服務端,而使用POST方法的請求則會攜帶請求實體,在請求實體中帶有傳給服務端的資料。

Content-Type

Content-Type請求頭部(Header)中一個用於指請求實體型別的內容頭部,在請求或響應用於指請求實體到底存放什麼樣的資料,所以只有會推帶請求實體的方法起作用,如POST方法。

在一般Web開發中,Content-Type最常用取值有下面四種:

  1. application/json:JSON資料

  2. application/x-www-form-urlencoded:form表單請求使用的型別,在傳送前會編碼所有字元

  3. multipart/form-data:不對字元編碼,一般用於檔案上傳

  4. text/html:一般用於響應中的響應頭,告訴客戶端返回的是HTML文件。

查詢引數(query)

查詢引數是URL中?後面跟著的部分,比如在掘金的搜尋框中輸入:Go,我們會看到瀏覽器的位址列變成:

juejin.im/search?quer…

查詢引數就是指query=Go&type=1,查詢引數由&分隔開,這是GET方法攜帶資料的方式,Go語言中支援獲取查詢引數部分的引數。

請求實體(body)

請求實體是一次Web請求中資料攜帶部分,一般只有POST請求才有這個部分,伺服器由Content-Type首部來判斷請求實體的內容編碼格式,如果想向伺服器傳送大量資料,一般都用POST請求。

Go處理Web請求資料

在Go語言中,使用http.Request結構來處理http請求的資料,在我們定義處理請求的方法,會傳入http.Request的例項,如下程式碼中request就是代表一個請求的例項。

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    //使用request可以獲取http請求的資料
})
複製程式碼

在golang官方文件中,可以看到http.Request的包外可訪問方法列表:

Go Web如何處理Web請求?

http.Request方法列表

下面是http.Request公開可訪問的欄位

type Request struct {
        Method string //方法:POST,GET...
        URL *url.URL //URL結構體
        Proto      string // 協議:"HTTP/1.0"
        ProtoMajor int    // 1
        ProtoMinor int    // 0
        Header Header    //頭部資訊
        Body io.ReadCloser //請求實體
        GetBody func() (io.ReadCloser, error) // Go 1.8
        ContentLength int64  //首部:Content-Length
        TransferEncoding []string
        Close bool           //是否已關閉
        Host string          //首部Host
        Form url.Values      //引數查詢的資料
        PostForm url.Values // application/x-www-form-urlencoded型別的body解碼後的資料
        MultipartForm *multipart.Form //檔案上傳時的資料
        Trailer Header
        RemoteAddr string          //請求地址
        RequestURI string          //請求的url地址
        TLS *tls.ConnectionState
        Cancel <-chan struct{} // 
        Response *Response //      響應資料
}
複製程式碼

獲得請求頭(Header)

對於常用的請求頭部資訊,http.Request結構有對應的欄位和方法,如下所示:

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    request.RemoteAddr
    request.RequestURI
    request.ContentLength 
    request.Proto
    request.Method 
    request.Referer()
    request.UserAgent()
})
複製程式碼

當然,其他的首頁,可以通過request.Header欄位來獲取,request.Header的定義如下所示:

type Header map[string][]string
複製程式碼

也就是說,request.Header是一個的型別是map,另外request.Header也提供相應的方法,如下所示:

Go Web如何處理Web請求?

也就是說,我們除了使用上面的方法獲取頭部資訊外,也可以使用request.Header來獲取,示例:

http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
    request.Header.Get("Content-Type")//返回的是string
    request.Header["Content-Type"] //返回的是[]string
})

複製程式碼

獲取查詢引數(Query)

如何獲取查詢引數(url中?後面使用&分隔的部分)呢?可以使用request.FormValue(key)方法獲取查詢引數,其中key為引數的名稱,程式碼如下:

package main
import (
	"fmt"
	"net/http"
)
func main() {
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        username := request.FormValue("username")
        gender := request.FormValue("gender")
        fmt.Fprintln(writer,fmt.Sprintf("使用者名稱:%s,性別:%s",username,gender))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
複製程式碼

在Postman輸入http://localhost:8080/hello?username=test&gender=男

Go Web如何處理Web請求?

獲取表單資訊(Form)

我們說獲取表單資訊,一般是指獲取Content-Type是application/x-www-form-urlencodedmultipart/form-data時,請求實體中的資料,如果你有做傳統網頁中的表單提交資料的經歷,相信對這兩種提交資料的方式應該是熟悉的,而multipart/form-data一般是用來上傳檔案的。

application/x-www-form-urlencoded

獲取Content-Type為application/x-www-form-urlencoded時提交上來的資料,可以使用request.PostForm欄位request.Form和request.PostFormValue(key)方法獲取,但必須先呼叫request.ParseForm()將資料寫入request.PostForm欄位中。

步驟為:

  1. 使用request.ParseForm()函式解析body引數,這時會將引數寫入Form欄位和PostForm欄位當中。
  2. 使用request.Form、request.PostForm或request.PostFormValue(key)都可以獲取

注意,request.Form和request.PostForm的型別url.Values,結構定義如下:

type Values map[string][]string
複製程式碼

示例如下:

package main
import (
	"fmt"
	"net/http"
)
func main(){
    http.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
        err := request.ParseForm()
        if err != nil{
        fmt.Fprintln(writer,"解析錯誤")
        }
        username1 := request.PostForm["username"][0]
        username2 := request.PostFormValue("username")
        username3 := request.Form["username"][0]
        fmt.Fprintln(writer,fmt.Sprintf("username1:%s,username2:%s,usernam3:%s",username1,username2,username3))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
複製程式碼

使用Postman輸入http://localhost:8080/hello,結果如下:

Go Web如何處理Web請求?

multipart/form-data

獲取Content-Typemultipart/form-data時提交上來的資料,步驟如下:

  1. 使用request.ParseMultipartForm(maxMemory),解析引數,將引數寫入到MultipartForm欄位當中,其中maxMemory為上傳檔案最大記憶體。
  2. 使用request.FormFile(檔案域),可以獲取上傳的檔案物件:multipart.File
  3. 除了檔案域,其中引數可以從request.PostForm欄位獲取,注意,此時不需要再呼叫request.ParseForm()了。
package main
import (
	"fmt"
	"net/http"
)
func main() {
    http.HandleFunc("/upload", func(writer http.ResponseWriter, request *http.Request) {
        err := request.ParseMultipartForm(32 << 20)
        if err != nil {
            fmt.Fprintln(writer,"檔案上傳錯誤")
            return
        }
        fmt.Println(request.FormFile("file"))
    })
    fmt.Println(http.ListenAndServe(":8080",nil))
}
複製程式碼

總結

上面簡單地介紹了使用Go語言如何獲取http請求提交上來的資料,重點為獲了表單資料,但其實在現在前後端分離開發趨勢和APP開發中,Content-Type指application/json是更常見的資料提交方式,以後有空可以學一下。

相關文章