日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

easyui datagrid url不请求请求_Go Web编程--深入学习解析HTTP请求

發(fā)布時(shí)間:2024/9/27 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 easyui datagrid url不请求请求_Go Web编程--深入学习解析HTTP请求 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前這個(gè)系列的文章一直在講用Go語(yǔ)言怎么編寫(xiě)HTTP服務(wù)器來(lái)提供服務(wù),如何給服務(wù)器配置路由來(lái)匹配請(qǐng)求到對(duì)應(yīng)的處理程序,如何添加中間件把一些通用的處理任務(wù)從具體的Handler中解耦出來(lái),以及如何更規(guī)范地在項(xiàng)目中應(yīng)用數(shù)據(jù)庫(kù)。不過(guò)一直漏掉了一個(gè)環(huán)節(jié)是服務(wù)器接收到請(qǐng)求后如何解析請(qǐng)求拿到想要的數(shù)據(jù),Go語(yǔ)言使用net/http包中的Request結(jié)構(gòu)體對(duì)象來(lái)表示HTTP請(qǐng)求,通過(guò)Request結(jié)構(gòu)對(duì)象上定義的方法和數(shù)據(jù)字段,應(yīng)用程序能夠便捷地訪問(wèn)和設(shè)置HTTP請(qǐng)求中的數(shù)據(jù)。

一般服務(wù)端解析請(qǐng)求的需求有如下幾種

  • HTTP請(qǐng)求頭中的字段值
  • URL 查詢字符串中的字段值
  • 請(qǐng)求體中的Form表單數(shù)據(jù)
  • 請(qǐng)求體中的JSON格式數(shù)據(jù)
  • 讀取客戶端的上傳的文件

今天這篇文章我們就按照這幾種常見(jiàn)的服務(wù)端對(duì)HTTP請(qǐng)求的操作來(lái)說(shuō)一下服務(wù)器應(yīng)用程序如何通過(guò)Request對(duì)象解析請(qǐng)求頭和請(qǐng)求體。

Request 結(jié)構(gòu)定義

在說(shuō)具體操作的使用方法之前我們先來(lái)看看net/http包中Request結(jié)構(gòu)體的定義,了解一下Request擁有什么樣的數(shù)據(jù)結(jié)構(gòu)。Request結(jié)構(gòu)在源碼中的定義如下。

type Request struct {Method stringURL *url.URLProto string // "HTTP/1.0"ProtoMajor int // 1ProtoMinor int // 0Header HeaderBody io.ReadCloserGetBody func() (io.ReadCloser, error)ContentLength int64TransferEncoding []stringClose boolHost stringForm url.ValuesPostForm url.ValuesMultipartForm *multipart.FormTrailer HeaderRemoteAddr stringRequestURI stringTLS *tls.ConnectionStateCancel <-chan struct{}Response *Responsectx context.Context }

我們快速地了解一下每個(gè)字段大致的含義,了解了每個(gè)字段的含義在不同的應(yīng)用場(chǎng)景下需要讀取訪問(wèn)HTTP請(qǐng)求的不同部分時(shí)就能夠有的放矢了。

Method

指定HTTP方法(GET,POST,PUT等)。

URL

URL指定要請(qǐng)求的URI(對(duì)于服務(wù)器請(qǐng)求)或要訪問(wèn)的URL(用于客戶請(qǐng)求)。它是一個(gè)表示URL的類型url.URL的指針,url.URL的結(jié)構(gòu)定義如下:

type URL struct {Scheme stringOpaque stringUser *UseriHost stringPath stringRawPath stringForceQuery bool RawQuery stringFragment string }

Proto

Proto,ProtoMajor,ProtoMinor三個(gè)字段表示傳入服務(wù)器請(qǐng)求的協(xié)議版本。對(duì)于客戶請(qǐng)求,這些字段將被忽略。 HTTP客戶端代碼始終使用HTTP / 1.1或HTTP / 2。

Header

Header包含服務(wù)端收到或者由客戶端發(fā)送的HTTP請(qǐng)求頭,該字段是一個(gè)http.Header類型的指針,http.Header類型的聲明如下:

type Header map[string][]string

是map[string][]string類型的別名,http.Header類型實(shí)現(xiàn)了GET,SET,Add等方法用于存取請(qǐng)求頭。如果服務(wù)端收到帶有如下請(qǐng)求頭的請(qǐng)求:

Host: example.com accept-encoding: gzip, deflate Accept-Language: en-us fOO: Bar foo: two

那么Header的值為:

Header = map[string][]string{"Accept-Encoding": {"gzip, deflate"},"Accept-Language": {"en-us"},"Foo": {"Bar", "two"}, }

對(duì)于傳入的請(qǐng)求,Host標(biāo)頭被提升為Request.Host字段,并將其從Header對(duì)象中刪除。HTTP 定義頭部的名稱是不區(qū)分大小寫(xiě)的。Go使用CanonicalHeaderKey實(shí)現(xiàn)的請(qǐng)求解析器使得請(qǐng)求頭名稱第一個(gè)字母以及跟隨在短橫線后的第一個(gè)字母大寫(xiě)其他都為小寫(xiě)形式,比如:Content-Length。對(duì)于客戶端請(qǐng)求,某些標(biāo)頭,例如Content-Length和Connection會(huì)在需要時(shí)自動(dòng)寫(xiě)入,并且標(biāo)頭中的值可能會(huì)被忽略。

Body

這個(gè)字段的類型是io.ReadCloser,Body是請(qǐng)求的主體。對(duì)于客戶端發(fā)出的請(qǐng)求,nil主體表示該請(qǐng)求沒(méi)有Body,例如GET請(qǐng)求。 HTTP客戶端的傳輸會(huì)負(fù)責(zé)調(diào)用Close方法。對(duì)于服務(wù)器接收的請(qǐng)求,請(qǐng)求主體始終為非nil,但如果請(qǐng)求沒(méi)有主體,則將立即返回EOF。服務(wù)器將自動(dòng)關(guān)閉請(qǐng)求主體。服務(wù)器端的處理程序不需要關(guān)心此操作。

GetBody

客戶端使用的方法的類型,其聲明為:

GetBody func() (io.ReadCloser, error)

ContentLength

ContentLength記錄請(qǐng)求關(guān)聯(lián)內(nèi)容的長(zhǎng)度。值-1表示長(zhǎng)度未知。值>=0表示從Body 中讀取到的字節(jié)數(shù)。對(duì)于客戶請(qǐng)求,值為0且非nil的Body也會(huì)被視為長(zhǎng)度未知。

TransferEncoding

TransferEncoding為字符串切片,其中會(huì)列出從最外層到最內(nèi)層的傳輸編碼,TransferEncoding通常可以忽略;在發(fā)送和接收請(qǐng)求時(shí),分塊編碼會(huì)在需要時(shí)自動(dòng)被添加或者刪除。

Close

Close表示在服務(wù)端回復(fù)請(qǐng)求或者客戶端讀取到響應(yīng)后是否要關(guān)閉連接。對(duì)于服務(wù)器請(qǐng)求,HTTP服務(wù)器會(huì)自動(dòng)處理 并且處理程序不需要此字段。對(duì)于客戶請(qǐng)求,設(shè)置此字段為true可防止重復(fù)使用到相同主機(jī)的請(qǐng)求之間的TCP連接,就像已設(shè)置Transport.DisableKeepAlives一樣。

Host

對(duì)于服務(wù)器請(qǐng)求,Host指定URL所在的主機(jī),為防止DNS重新綁定攻擊,服務(wù)器處理程序應(yīng)驗(yàn)證Host標(biāo)頭具有的值。 http庫(kù)中的ServeMux(復(fù)用器)支持注冊(cè)到特定Host的模式,從而保護(hù)其注冊(cè)的處理程序。對(duì)于客戶端請(qǐng)求,Host可以用來(lái)選擇性地覆蓋請(qǐng)求頭中的Host,如果不設(shè)置,Request.Write使用URL.Host來(lái)設(shè)置請(qǐng)求頭中的Host。

Form

Form包含已解析的表單數(shù)據(jù),包括URL字段的查詢參數(shù)以及PATCH,POST或PUT表單數(shù)據(jù)。此字段僅在調(diào)用Request.ParseForm之后可用。HTTP客戶端會(huì)忽略Form并改用Body。Form字段的類型是url.Values類型的指針。url.Values類型的聲明如下:

type Values map[string][]string

也是map[string][]string類型的別名。url.Values類型實(shí)現(xiàn)了GET,SET,Add,Del等方法用于存取表單數(shù)據(jù)。

PostForm

PostForm類型與Form字段一樣,包含來(lái)自PATCH,POST的已解析表單數(shù)據(jù)或PUT主體參數(shù)。此字段僅在調(diào)用ParseForm之后可用。HTTP客戶端會(huì)忽略PostForm并改用Body。

MultipartForm

MultipartForm是已解析的多部分表單數(shù)據(jù),包括文件上傳。僅在調(diào)用Request.ParseMultipartForm之后,此字段才可用。HTTP客戶端會(huì)忽略MultipartForm并改用Body。該字段的類型是*multipart.Form。

RemoteAddr

RemoteAddr允許HTTP服務(wù)器和其他軟件記錄發(fā)送請(qǐng)求的網(wǎng)絡(luò)地址,通常用于記錄。 net/http包中的HTTP服務(wù)器在調(diào)用處理程序之前將RemoteAddr設(shè)置為“ IP:端口”, HTTP客戶端會(huì)忽略此字段。

RequestURI

RequestURI是未修改的request-target客戶端發(fā)送的請(qǐng)求行(RFC 7230,第3.1.1節(jié))。在服務(wù)器端,通常應(yīng)改用URL字段。在HTTP客戶端請(qǐng)求中設(shè)置此字段是錯(cuò)誤的。

Response

Response字段類型為*Response,它指定了導(dǎo)致此請(qǐng)求被創(chuàng)建的重定向響應(yīng),此字段僅在客戶端發(fā)生重定向時(shí)被填充。

ctx

ctx 是客戶端上下文或服務(wù)器上下文。它應(yīng)該只通過(guò)使用WithContext復(fù)制整個(gè)Request進(jìn)行修改。這個(gè)字段未導(dǎo)出以防止人們錯(cuò)誤使用Context并更改同一請(qǐng)求的調(diào)用方所擁有的上下文。

讀取請(qǐng)求頭

上面分析了Go將HTTP請(qǐng)求頭存儲(chǔ)在Request結(jié)構(gòu)體對(duì)象的Header字段里,Header字段實(shí)質(zhì)上是一個(gè)Map,請(qǐng)求頭的名稱為Mapkey,Map Value的類型為字符串切片,有的請(qǐng)求頭像Accept會(huì)有多個(gè)值,在切片中就對(duì)應(yīng)多個(gè)元素。

Header類型的Get方法可以獲取請(qǐng)求頭的第一個(gè)值,

func exampleHandler(w http.ResponseWriter, r *http.Request) {ua := r.Header.Get("User-Agent")... }

或者是獲取值時(shí)直接通過(guò)key獲取對(duì)應(yīng)的切片值就好,比如將上面的改為:

ua := r.Header["User-Agent"]

下面我們寫(xiě)個(gè)遍歷請(qǐng)求頭信息的示例程序,同時(shí)也會(huì)通上面介紹的Request結(jié)構(gòu)中定義的Method,URL,Host,RemoteAddr等字段把請(qǐng)求的通用信息打印出來(lái)。在我們一直使用的http_demo項(xiàng)目中增加一個(gè)DisplayHeadersHandler,其源碼如下:

package handlerimport ("fmt""net/http" )func DisplayHeadersHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Method: %s URL: %s Protocol: %s n", r.Method, r.URL, r.Proto)// 遍歷所有請(qǐng)求頭for k, v := range r.Header {fmt.Fprintf(w, "Header field %q, Value %qn", k, v)}fmt.Fprintf(w, "Host = %qn", r.Host)fmt.Fprintf(w, "RemoteAddr= %qn", r.RemoteAddr)// 通過(guò) Key 獲取指定請(qǐng)求頭的值fmt.Fprintf(w, "nnFinding value of "Accept" %q", r.Header["Accept"]) }

將其處理程序綁定到/index/display_headers路由上:

indexRouter.HandleFunc("/display_headers", handler.DisplayHeadersHandler)

然后啟動(dòng)項(xiàng)目,打開(kāi)瀏覽器訪問(wèn):

http://localhost:8000/index/display_headers

可以看到如下輸出:

http_demo項(xiàng)目中已經(jīng)添加了本文中所有示例的源碼,關(guān)注文末公眾號(hào)回復(fù)gohttp06可以獲取源碼的下載鏈接。

獲取URL參數(shù)值

GET請(qǐng)求中的URL查詢字符串中的參數(shù)可以通過(guò)url.Query(),我們來(lái)看一下啊url.Query()函數(shù)的源碼:

func (u *URL) Query() Values {v, _ := ParseQuery(u.RawQuery)return v }

它通過(guò)ParseQuery函數(shù)解析URL參數(shù)然后返回一個(gè)url.Values類型的值。url.Values類型上面我們已經(jīng)介紹過(guò)了是map[string][]string類型的別名,實(shí)現(xiàn)了GET,SET,Add,Del等方法用于存取數(shù)據(jù)。

所以我們可以使用r.URL.Query().Get("ParamName")獲取參數(shù)值,也可以使用r.URL.Query()["ParamName"]。兩者的區(qū)別是Get只返回切片中的第一個(gè)值,如果參數(shù)對(duì)應(yīng)多個(gè)值時(shí)(比如復(fù)選框表單那種請(qǐng)求就是一個(gè)name對(duì)應(yīng)多個(gè)值),記住要使用第二種方式。

我們通過(guò)運(yùn)行一個(gè)示例程序display_url_params.go來(lái)看一下兩種獲取URL參數(shù)的區(qū)別

package handlerimport ( "fmt" "net/http" )func DisplayUrlParamsHandler(w http.ResponseWriter, r *http.Request) {for k, v := range r.URL.Query() {fmt.Fprintf(w, "ParamName %q, Value %qn", k, v)fmt.Fprintf(w, "ParamName %q, Get Value %qn", k, r.URL.Query().Get(k))} }

將其處理程序綁定到/index/display_url_params路由上:

indexRouter.HandleFunc("/display_url_params", handler.DisplayUrlParamsHandler)

打開(kāi)瀏覽器訪問(wèn)

http://localhost:8000/index/display_url_params?a=b&c=d&a=c

瀏覽器會(huì)輸出:

ParamName "a", Value ["b" "c"] ParamName "a", Get Value "b" ParamName "c", Value ["d"] ParamName "c", Get Value "d"

我們?yōu)閰?shù)a傳遞了兩個(gè)參數(shù)值,可以看到通過(guò)url.Query.Get()只能讀取到第一個(gè)參數(shù)值。

獲取表單中的參數(shù)值

Request結(jié)構(gòu)的Form字段包含已解析的表單數(shù)據(jù),包括URL字段的查詢參數(shù)以及PATCH,POST或PUT表單數(shù)據(jù)。此字段僅在調(diào)用Request.ParseForm之后可用。不過(guò)Request對(duì)象提供一個(gè)FormValue方法來(lái)獲取指定名稱的表單數(shù)據(jù),FormValue方法會(huì)根據(jù)Form字段是否有設(shè)置來(lái)自動(dòng)執(zhí)行ParseForm方法。

func (r *Request) FormValue(key string) string {if r.Form == nil {r.ParseMultipartForm(defaultMaxMemory)}if vs := r.Form[key]; len(vs) > 0 {return vs[0]}return "" }

可以看到FormValue方法也是只返回切片中的第一個(gè)值。如果需要獲取字段對(duì)應(yīng)的所有值,那么需要通過(guò)字段名訪問(wèn)Form字段。如下:

獲取表單字段的單個(gè)值

r.FormValue(key)

獲取表單字段的多個(gè)值

r.ParseForm()r.Form["key"]

下面是我們的示例程序,以及對(duì)應(yīng)的路由:

//handler/display_form_data.go package handlerimport ("fmt""net/http" )func DisplayFormDataHandler(w http.ResponseWriter, r *http.Request) {if err := r.ParseForm(); err != nil {panic(err)}for key, values := range r.Form {fmt.Fprintf(w, "Form field %q, Values %qn", key, values)fmt.Fprintf(w, "Form field %q, Value %qn", key, r.FormValue(key))} }//router.go indexRouter.HandleFunc("/display_form_data", handler.DisplayFormDataHandler)

我們?cè)诿钚兄惺褂胏URL命令發(fā)送表單數(shù)據(jù)到處理程序,看看效果。

curl -X POST -d 'username=James&password=123' http://localhost:8000/index/display_form_data

返回的響應(yīng)如下:

Form field "username", Values ["James"] Form field "username", Value "James" Form field "password", Values ["123"] Form field "password", Value "123"

獲取 Cookie

Request對(duì)象專門(mén)提供了一個(gè)Cookie方法用來(lái)訪問(wèn)請(qǐng)求中攜帶的Cookie數(shù)據(jù),方法會(huì)返回一個(gè)*Cookie類型的值以及error。Cookie類型的定義如下:

type Cookie struct {Name stringValue stringPath string // optionalDomain string // optionalExpires time.Time // optionalRawExpires string // for reading cookies onlyMaxAge intSecure boolHttpOnly boolSameSite SameSiteRaw stringUnparsed []string }

所以要讀取請(qǐng)求中指定名稱的Cookie值,只需要

cookie, err := r.Cookie(name) // 錯(cuò)誤檢查 ... value := cookie.Value

Request.Cookies()方法會(huì)返回[]*Cookie切片,其中會(huì)包含請(qǐng)求中所有的Cookie

下面的示例程序,會(huì)打印請(qǐng)求中所有的Cookie

// handler/read_cookie.go package handlerimport ("fmt""net/http" )func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {for _, cookie := range r.Cookies() {fmt.Fprintf(w, "Cookie field %q, Value %qn", cookie.Name, cookie.Value)} } //router/router.go indexRouter.HandleFunc("/read_cookie", handler.ReadCookieHandler)

我們通過(guò)cURL在命令行請(qǐng)求http://localhost:8000/index/read_cookie

curl --cookie "USER_TOKEN=Yes" http://localhost:8000/index/read_cookie

執(zhí)行命令后會(huì)返回:

Cookie field "USER_TOKEN", Value "Yes"

解析請(qǐng)求體中的JSON數(shù)據(jù)

現(xiàn)在前端都傾向于把請(qǐng)求數(shù)據(jù)以JSON格式放到請(qǐng)求主體中傳給服務(wù)器,針對(duì)這個(gè)使用場(chǎng)景,我們需要把請(qǐng)求體作為json.NewDecoder()的輸入流,然后將請(qǐng)求體中攜帶的JSON格式的數(shù)據(jù)解析到聲明的結(jié)構(gòu)體變量中

//handler/parse_json_request package handlerimport ("encoding/json""fmt""net/http" )type Person struct {Name stringAge int }func DisplayPersonHandler(w http.ResponseWriter, r *http.Request) {var p Person// 將請(qǐng)求體中的 JSON 數(shù)據(jù)解析到結(jié)構(gòu)體中// 發(fā)生錯(cuò)誤,返回400 錯(cuò)誤碼err := json.NewDecoder(r.Body).Decode(&p)if err != nil {http.Error(w, err.Error(), http.StatusBadRequest)return}fmt.Fprintf(w, "Person: %+v", p) }// router/router.go indexRouter.HandleFunc("/parse_json_request", handler.ParseJsonRequestHandler)

在命令行里用cURL命令測(cè)試我們的程序:

curl -X POST -d '{"name": "James", "age": 18}' -H "Content-Type: application/json" http://localhost:8000/index/parse_json_request

返回響應(yīng)如下:

Person: {Name:James Age:18}%

讀取上傳文件

服務(wù)器接收客戶端上傳的文件,使用Request定義的FormFile()方法。該方法會(huì)自動(dòng)調(diào)用r.ParseMultipartForm(32 << 20)方法解析請(qǐng)求多部表單中的上傳文件,并把文件可讀入內(nèi)存的大小設(shè)置為32M(32向左位移20位),如果內(nèi)存大小需要單獨(dú)設(shè)置,就要在程序里單獨(dú)調(diào)用ParseMultipartForm()方法才行。

func ReceiveFile(w http.ResponseWriter, r *http.Request) {r.ParseMultipartForm(32 << 20) var buf bytes.Bufferfile, header, err := r.FormFile("file")if err != nil {panic(err)}defer file.Close()name := strings.Split(header.Filename, ".")fmt.Printf("File name %sn", name[0])io.Copy(&buf, file)contents := buf.String()fmt.Println(contents)buf.Reset()return }

Go語(yǔ)言解析HTTP請(qǐng)求比較常用的方法我們都介紹的差不多了。因?yàn)橄肟偨Y(jié)全一點(diǎn),篇幅還是有點(diǎn)長(zhǎng),不過(guò)整體不難懂,而且也可以下載程序中的源碼自己運(yùn)行調(diào)試,動(dòng)手實(shí)踐一下更有助于理解吸收。HTTP客戶端發(fā)送請(qǐng)求要設(shè)置的內(nèi)容也只今天講的Request結(jié)構(gòu)體的字段,Request對(duì)象也提供了一些設(shè)置相關(guān)的方法供開(kāi)發(fā)人員使用,今天就先說(shuō)這么多了。

關(guān)注下方公眾號(hào)回復(fù)gohttp06可以下載文章中項(xiàng)目的源碼,趕快下載下來(lái)自己試一試吧。

前文回顧

深入學(xué)習(xí)用Go編寫(xiě)HTTP服務(wù)器

Web服務(wù)器路由

十分鐘學(xué)會(huì)用Go編寫(xiě)Web中間件

Go Web編程--應(yīng)用ORM

總結(jié)

以上是生活随笔為你收集整理的easyui datagrid url不请求请求_Go Web编程--深入学习解析HTTP请求的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。