欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在Golang中正確的修改HTTPRequest的Host的操作方法

 更新時間:2023年12月31日 08:33:09   作者:Kearth  
我們工作中經(jīng)常需要通過HTTP請求Server的服務(wù),比如腳本批量請求接口跑數(shù)據(jù),由于一些網(wǎng)關(guān)策略,部分Server會要求請求中Header里面附帶Host參數(shù),所以本文給大家介紹了如何在Golang中正確的修改HTTPRequest的Host,需要的朋友可以參考下

背景

我們工作中經(jīng)常需要通過HTTP請求Server的服務(wù),比如腳本批量請求接口跑數(shù)據(jù)。在這個過程中,由于一些網(wǎng)關(guān)策略,部分Server會要求請求中Header里面附帶Host參數(shù)。這時,我們可能會想到在Header里面直接賦值Host,比如這樣:

req.Header.Add("Host", "www.example.com")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

但請求的過程中會發(fā)現(xiàn)明明設(shè)置了,接收方卻收不到這個Host。因此下面我會闡述為什么會這樣,以及如何正確的修改HTTPRequest的Host。

為什么會這樣

首先我們打印一下Header.Add后的參數(shù)看看會怎樣

map[Host:[www.example.com]]

再排除世界上有鬼的情況下,我們可以合理分析出: Header.Add環(huán)節(jié)既然成功了,那么Host一定是在實際請求HTTP前被替換了

由于下一段代碼就是client.Do,因此有理由懷疑這個操作在Do方法里面

// 發(fā)送請求并獲取響應(yīng)
resp, err := client.Do(req)
if err != nil {
	fmt.Println("發(fā)送請求失敗:", err)
	return
}

追蹤下去,可以看到net/http包的源碼如下:

func (c *Client) Do(req *Request) (*Response, error) {
	return c.do(req)
}
func (c *Client) do(req *Request) (retres *Response, reterr error) {
    ... ... // 省略
    host := ""
	if req.Host != "" && req.Host != req.URL.Host {
		// If the caller specified a custom Host header and the
		// redirect location is relative, preserve the Host header
		// through the redirect. See issue #22233.
		if u, _ := url.Parse(loc); u != nil && !u.IsAbs() {
			host = req.Host
		}
	}
	ireq := reqs[0]
	req = &Request{
		Method:   redirectMethod,
		Response: resp,
		URL:      u,
		Header:   make(Header),
		Host:     host,
		Cancel:   ireq.Cancel,
		ctx:      ireq.ctx,
	}
    ... ... // 省略
}

這段指明:請求實際使用的Host默認為空。如果req.Host字段不為空,且不與URL的Host相同,會使用req.Host

// If the caller specified a custom Host header and the redirect location is relative, preserve the Host header through the redirect.
// 如果調(diào)用者指定了自定義的 Host 標頭并且重定向位置是相對路徑的話,通過重定向保留該 Host 標頭。

那么我們來看看req.Host字段是什么

	// For server requests, Host specifies the host on which the
	// URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this
	// is either the value of the "Host" header or the host name
	// given in the URL itself. For HTTP/2, it is the value of the
	// ":authority" pseudo-header field.
	// It may be of the form "host:port". For international domain
	// names, Host may be in Punycode or Unicode form. Use
	// golang.org/x/net/idna to convert it to either format if
	// needed.
	// To prevent DNS rebinding attacks, server Handlers should
	// validate that the Host header has a value for which the
	// Handler considers itself authoritative. The included
	// ServeMux supports patterns registered to particular host
	// names and thus protects its registered Handlers.
	//
	// For client requests, Host optionally overrides the Host
	// header to send. If empty, the Request.Write method uses
	// the value of URL.Host. Host may contain an international
	// domain name.
	Host string

這段注釋主要解釋了在 Go 語言中如何處理請求的 Host 標頭。在服務(wù)器請求中,Host 指定要查找 URL 的主機,可能是 Host 標頭的值或 URL 本身中給定的主機名。對于客戶端請求,Host 可以選擇性地覆蓋要發(fā)送的 Host 標頭,如果為空,則使用 URL.Host 的值。此外,還提到了國際化域名的處理和防止 DNS 重新綁定攻擊的注意事項。

這基本跟我們上文的結(jié)論相互印證了,至此我們搞清楚了為什么Header里面的Host不生效:因為Do使用HTTP Request里面的Host字段,且不是Header里面的Host鍵對應(yīng)值

怎么解決

顯然,指明 req.Host 是一個較好的方案

req.Host = "www.example.com"

至此我們解決了這個問題

我們還能知道些什么

關(guān)于 issue #22233

if req.Host != "" && req.Host != req.URL.Host {
    // If the caller specified a custom Host header and the
    // redirect location is relative, preserve the Host header
    // through the redirect. See issue #22233.
    if u, _ := url.Parse(loc); u != nil && !u.IsAbs() {
        host = req.Host
    }
}

我們注意到在這段代碼中,提到了issue #22233,那么它到底是什么呢,我們一起來看看!

這個問題 #issue 22233 是2017年由 timonwong 提出的,當(dāng)時版本是 go1.9.1 darwin/amd64。問題內(nèi)容是:客戶端跟隨重定向時不會保留 Host 標頭 golang的一位維護者tombergan 響應(yīng)了這個問題: 認為這絕對是個bug

但同時他也提出重定向時復(fù)制哪些header內(nèi)容是沒有一個較好的確切的指導(dǎo)的。

Parent:     645c661a (cmd/compile/internal/syntax: factor out list parsing)
Author:     Tom Bergan <tombergan@google.com>
AuthorDate: 2017-10-13 15:56:37 -0700
Commit:     Tom Bergan <tombergan@google.com>
CommitDate: 2017-10-16 17:44:26 +0000
net/http: preserve Host header following a relative redirect
If the client sends a request with a custom Host header and receives
a relative redirect in response, the second request should use the
same Host header as the first request. However, if the response is
an abolute redirect, the Host header should not be preserved. See
further discussion on the issue tracker.
Fixes #22233
Change-Id: I8796e2fbc1c89b3445e651f739d5d0c82e727c14
Reviewed-on: https://go-review.googlesource.com/70792
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

最終于2017-10-16這次提交中他修復(fù)了這個問題,從郵箱看這位大神應(yīng)該是google的一位員工。代碼改動如下:

至此我們了解了有關(guān)于 issue #22233 的全部

關(guān)于 Host 是什么

在前文中,Request的Host屬性的注釋中提到: Host指定了正在尋找的主機。

    // For server requests, Host specifies the host on which the
    // URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this
    // is either the value of the "Host" header or the host name
    // given in the URL itself. For HTTP/2, it is the value of the
    // ":authority" pseudo-header field.

從這里面提到的 RFC 7230,section 5.4 可以看到

① Host提供目標URI的主機、端口信息,使服務(wù)器在單個IP地址上可以根據(jù)不同的主機名提供不同的服務(wù)和資源。(比如單機部署多個網(wǎng)站

② HTTP/1.1必須發(fā)送Host字段。當(dāng)代理服務(wù)接受到absolute-form形式的請求時,忽略Host字段,取請求中的主機信息。轉(zhuǎn)發(fā)請求的時候需要基于接收的請求重新生成Host,而不是轉(zhuǎn)發(fā)接受到的Host。(URL里面的主機信息優(yōu)先級高于Host字段。轉(zhuǎn)發(fā)請求的時候Host字段不透傳

③ Host本身可以任意修改,因此如果依賴Host字段進行代理轉(zhuǎn)發(fā)、緩存密鑰、身份驗證等,需要先行校驗Host值的合法性,避免Host頭攻擊

④ 對于缺少或者有多個Host字段的HTTP/1.1請求消息,服務(wù)器需要返回400 Bad Request 狀態(tài)碼 (Host字段有且只能有一個

至此,我們弄明白了Host是什么

// example: www.example.org or www.example.org:8080
Host = uri-host [":" port]; 

以上就是在Golang中正確的修改HTTPRequest的Host的操作方法的詳細內(nèi)容,更多關(guān)于Golang修改HTTPRequest的Host的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang語言實現(xiàn)gRPC的具體使用

    Golang語言實現(xiàn)gRPC的具體使用

    本文主要介紹了Golang語言實現(xiàn)gRPC的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • golang中一種不常見的switch語句寫法示例詳解

    golang中一種不常見的switch語句寫法示例詳解

    這篇文章主要介紹了golang中一種不常見的switch語句寫法,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • Golang利用casbin實現(xiàn)權(quán)限驗證詳解

    Golang利用casbin實現(xiàn)權(quán)限驗證詳解

    Casbin是一個強大的、高效的開源訪問控制框架,其權(quán)限管理機制支持多種訪問控制模型,Casbin只負責(zé)訪問控制。本文將利用casbin實現(xiàn)權(quán)限驗證功能,需要的可以參考一下
    2023-02-02
  • Go1.21新增maps包的用法詳解

    Go1.21新增maps包的用法詳解

    maps?包提供了幾個非常有用的用于操作?map?類型(任何類型的?map)的函數(shù),本文為大家整理了部分函數(shù)的具體用法,感興趣的小伙伴可以了解一下
    2023-08-08
  • Golang使用ReverseProxy實現(xiàn)反向代理的方法

    Golang使用ReverseProxy實現(xiàn)反向代理的方法

    本文介紹了如何使用Golang的ReverseProxy實現(xiàn)反向代理,包括源碼結(jié)構(gòu)解析和官方單機示例NewSingleHostReverseProxy,同時指出,若要實現(xiàn)負載均衡,需要自行開發(fā),還提供了一個簡單的HTTP服務(wù)用于測試,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • golang validator參數(shù)校驗的實現(xiàn)

    golang validator參數(shù)校驗的實現(xiàn)

    這篇文章主要介紹了golang validator參數(shù)校驗的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • 詳解go語言中并發(fā)安全和鎖問題

    詳解go語言中并發(fā)安全和鎖問題

    這篇文章主要介紹了go語言中并發(fā)安全和鎖問題,包含互斥鎖解鎖過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • 特殊字符的json序列化總結(jié)大全

    特殊字符的json序列化總結(jié)大全

    這篇文章主要給大家介紹了關(guān)于特殊字符的json序列化的相關(guān)資料,通過示例代碼分別給大家介紹了關(guān)于python 、 rust 、 java 和golang對特殊字符的json序列化操作,需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • golang 獲取字符串長度的案例

    golang 獲取字符串長度的案例

    這篇文章主要介紹了golang 獲取字符串長度的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go map發(fā)生內(nèi)存泄漏解決方法

    Go map發(fā)生內(nèi)存泄漏解決方法

    這篇文章主要介紹了Go map發(fā)生內(nèi)存泄漏解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11

最新評論