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

go進行http請求偶發(fā)EOF問題分析

 更新時間:2025年01月09日 08:49:44   作者:刀山羊  
go使用連接池進行http請求,一般都能請求成功,但偶然會出現請求失敗返回EOF錯誤的情況,本文主要來帶大家分析一下為什么會出現這樣的問題并提供解決方法,需要的可以參考下

簡介

go使用連接池進行http請求,一般都能請求成功,但偶然會出現請求失敗返回EOF錯誤的情況;類似java的org.apache.http.NoHttpResponseException

分析

客戶端通過keep alive機制保障性能,簡單理解就是復用tcp五元會話,用于進行多次http請求;但如果服務端的空閑?;顣r間是10s,在第一次請求完的10s進行了第二次請求,此時客戶端認為連接仍然有效繼續(xù)發(fā)起請求,但服務端發(fā)出了FIN報文不再對此連接進行響應,從而導致客戶端請求失敗并出現EOF錯誤。

偶發(fā)就是因為兩個時間要恰好碰到一起才可能觸發(fā)這個問題

  • 服務器發(fā)送了FIN報文,但是客戶端還沒有收到,但是客戶端已經發(fā)送了請求數據包
  • 如果在服務器超時前發(fā)起了請求,那連接此時還可用,正常
  • 如果在服務器超時后發(fā)起了請求,那連接已經完成FIN關閉流程,請求會觸發(fā)新的會話,正常

解決方式:

  • 在出現EOF的時候,進行重試,此時會觸發(fā)新的五元組連接進行請求(推薦)
  • 設置客戶端的空閑?;顣r間小于服務端的空閑?;顣r間
    • IdleConnTimeout 此時客戶端會在超時時主動向服務端發(fā)送RST進行連接重置

代碼

package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"time"
)

func main() {
	// 創(chuàng)建自定義的 Transport,設置連接池參數
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true, // 忽略 TLS 證書驗證
		},
		MaxIdleConns:        1,                // 限制最大空閑連接數為1
		MaxIdleConnsPerHost: 1,                // 限制每個host最大空閑連接數為1
		IdleConnTimeout:     20 * time.Second, // 本地空閑連接超時設置為20s
		DisableKeepAlives:   false,            // 啟用 keep-alive
		MaxConnsPerHost:     1,                // 限制每個host的最大連接數為1,強制復用連接
		ForceAttemptHTTP2:   false,            // 禁用 HTTP/2
	}

	// 創(chuàng)建 HTTP 客戶端
	client := &http.Client{
		Transport: tr,
		Timeout:   5 * time.Second, // 設置請求超時時間
	}

	// 準備請求參數
	url := "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977"
	cookie := "session-id=f416b188c91bc72a06853b362d5cb7b3a6b68a43"

	// 準備請求體數據
	requestBody := map[string]string{
		"sys_name": "N-GUARD",
	}
	// 將 map 轉換為 JSON
	jsonBody, err := json.Marshal(requestBody)
	if err != nil {
		fmt.Printf("JSON 編碼失敗: %v\n", err)
	}

	// 循環(huán)發(fā)送請求,模擬使用已關閉的連接
	for i := 0; i < 5; i++ { // 只測試兩次請求即可

		// 每次請求都創(chuàng)建新的 bytes.Buffer,確保 Body 可以重復讀取
		bodyReader := bytes.NewBuffer(jsonBody)

		req, err := http.NewRequest("PUT", url, bodyReader)
		if err != nil {
			fmt.Printf("創(chuàng)建請求失敗: %v\n", err)
			continue
		}

		// 設置 Content-Length
		req.ContentLength = int64(len(jsonBody))
		// 設置請求頭
		req.Header.Set("Cookie", cookie)
		req.Header.Set("Content-Type", "application/json")

		fmt.Printf("發(fā)送第 %d 個請求...\n", i+1)
		// 發(fā)送請求
		resp, err := client.Do(req)
		if err != nil {
			fmt.Printf("請求失敗: %v\n", err)
			if errors.Is(err, io.EOF) {
				fmt.Printf("連接不再可用: 重試:新的五元重新發(fā)起連接\n")
				bodyReader := bytes.NewBuffer(jsonBody)

				reqretry, err := http.NewRequest("PUT", url, bodyReader)
				if err != nil {
					fmt.Printf("創(chuàng)建請求失敗: %v\n", err)
					continue
				}

				// 設置 Content-Length
				reqretry.ContentLength = int64(len(jsonBody))
				// 設置請求頭
				reqretry.Header.Set("Cookie", cookie)
				reqretry.Header.Set("Content-Type", "application/json")

				resp, err = client.Do(reqretry)
				if err != nil {
					fmt.Printf("err:\n", err)
					continue
				}
			} else {
				continue
			}
		}

		// 讀取響應
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Printf("讀取響應失敗: %v\n", err)
		}
		resp.Body.Close()

		fmt.Printf("請求 %d - 狀態(tài)碼: %d, 響應: %s\n", i+1, resp.StatusCode, string(body))

		fmt.Println("等待10秒后發(fā)送第二個請求...")
		time.Sleep(10 * time.Second) // 等待10秒,此時服務端已經關閉連接(10s)
		time.Sleep(500 * time.Millisecond)
	}
}

運行

[xiaofeng@localhost httpkeepalive]$ go run main.go 
發(fā)送第 1 個請求...
請求 1 - 狀態(tài)碼: 200, 響應: {"code":0,"result":"0","message":"成功"}
等待10秒后發(fā)送第二個請求...
發(fā)送第 2 個請求...
請求 2 - 狀態(tài)碼: 200, 響應: {"code":0,"result":"0","message":"成功"}
等待10秒后發(fā)送第二個請求...
發(fā)送第 3 個請求...
請求失敗: Put "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977": EOF
連接不再可用: 重試:新的五元重新發(fā)起連接
請求 3 - 狀態(tài)碼: 200, 響應: {"code":0,"result":"0","message":"成功"}
等待10秒后發(fā)送第二個請求...
發(fā)送第 4 個請求...
請求失敗: Put "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977": EOF
連接不再可用: 重試:新的五元重新發(fā)起連接
請求 4 - 狀態(tài)碼: 200, 響應: {"code":0,"result":"0","message":"成功"}
等待10秒后發(fā)送第二個請求...
發(fā)送第 5 個請求...
請求 5 - 狀態(tài)碼: 200, 響應: {"code":0,"result":"0","message":"成功"}
等待10秒后發(fā)送第二個請求...

報文

到此這篇關于go進行http請求偶發(fā)EOF問題分析的文章就介紹到這了,更多相關go http請求偶發(fā)EOF內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Go設計模式之迭代器模式講解和代碼示例

    Go設計模式之迭代器模式講解和代碼示例

    迭代器是一種行為設計模式, 讓你能在不暴露復雜數據結構內部細節(jié)的情況下遍歷其中所有的元素,本文將為大家詳細介紹Go 迭代器模式,文中詳細的代碼示例,需要的朋友可以參考下
    2023-07-07
  • Go使用chan或context退出協程示例詳解

    Go使用chan或context退出協程示例詳解

    這篇文章主要為大家介紹了Go使用chan或context退出協程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • 使用Go語言進行安卓開發(fā)的詳細教程

    使用Go語言進行安卓開發(fā)的詳細教程

    本文將介紹如何使用Go語言進行安卓開發(fā),我們將探討使用Go語言進行安卓開發(fā)的優(yōu)點、準備工作、基本概念和示例代碼,通過本文的學習,你將了解如何使用Go語言構建高效的安卓應用程序,需要的朋友可以參考下
    2023-11-11
  • Golang使用crypto/ed25519實現數字簽名和驗證

    Golang使用crypto/ed25519實現數字簽名和驗證

    本文將深入探討如何在?Golang?中使用?crypto/ed25519?進行數字簽名和驗證,我們將從基本原理開始,逐步引導讀者了解生成密鑰對、進行數字簽名,以及驗證簽名的具體過程,希望對大家有所幫助
    2024-02-02
  • Go語言如何高效的進行字符串拼接(6種方式對比分析)

    Go語言如何高效的進行字符串拼接(6種方式對比分析)

    本文主要介紹了Go語言如何高效的進行字符串拼接(6種方式對比分析),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • Go語言協程通道使用的問題小結

    Go語言協程通道使用的問題小結

    本文主要介紹了Go語言協程通道使用的問題小結,詳細的介紹了使用的一些重要問題,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-08-08
  • 淺談Go語言中的接口類型

    淺談Go語言中的接口類型

    Go語言中接口是一種抽象的類型,本文主要介紹了淺談Go語言中的接口類型,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-08-08
  • golang實現RPC模塊的示例

    golang實現RPC模塊的示例

    本文詳細介紹了在Go語言中如何實現RPC模塊,包括RPC服務端和客戶端的構建及代碼實現,同時提到了使用JSON-RPC的方法,通過簡單的步驟,可以實現跨進程的遠程過程調用,感興趣的可以了解一下
    2024-09-09
  • golang 如何替換掉字符串里面的換行符\n

    golang 如何替換掉字符串里面的換行符\n

    這篇文章主要介紹了golang 替換掉字符串里面的換行符\n操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Go Module依賴管理的實現

    Go Module依賴管理的實現

    Go Module是Go語言的官方依賴管理解決方案,其提供了一種簡單、可靠的方式來管理項目的依賴關系,本文主要介紹了Go Module依賴管理的實現,感興趣的可以了解一下
    2024-06-06

最新評論