首頁  >  文章  >  後端開發  >  如何修復 proxyconnect tcp: tls: 第一筆記錄看起來不像 TLS 握手

如何修復 proxyconnect tcp: tls: 第一筆記錄看起來不像 TLS 握手

王林
王林轉載
2024-02-11 10:18:07605瀏覽

如何修复 proxyconnect tcp: tls: 第一条记录看起来不像 TLS 握手

php小編蘋果在這裡為大家帶來解決"proxyconnect tcp: tls: 第一筆記錄看起來不像 TLS 握手"問題的方法。這種錯誤通常出現在使用代理伺服器時,可能會導致網路連線問題。在解決此問題之前,我們首先需要了解問題的根源。透過以下簡潔的步驟,我們將向您展示如何修復這個問題,以確保您的網路連線正常運作。

問題內容

在如何在 Go 中使用 REST API 中,提供了一個完全有效的範例程式碼來呼叫公共 REST API。但如果我嘗試範例,則會出現此錯誤:

error getting cat fact: 
      Get "https://catfact.ninja/fact": 
      proxyconnect tcp: tls: first record does not look like a TLS handshake

有關http狀態的文檔

<code>
For control over proxies, TLS configuration, keep-alives, compression, and other settings, create a Transport:
</code>

以及傳輸文件:

<code>    // DialContext specifies the dial function for creating unencrypted TCP connections.
    // If DialContext is nil (and the deprecated Dial below is also nil),
    // then the transport dials using package net.
    //
    // DialContext runs concurrently with calls to RoundTrip.
    // A RoundTrip call that initiates a dial may end up using
    // a connection dialed previously when the earlier connection
    // becomes idle before the later DialContext completes.
    DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
</code>

因此,我假設我必須設定 Dialcontext 才能啟用從客戶端到代理的不安全連線 without TLS。但我不知道該怎麼做。閱讀這些:

  • 如何在golang中進行代理程式和TLS;
  • 如何透過代理程式進行 HTTP/HTTPS GET;和
  • 如何使用錯誤的憑證執行 https 要求?

也沒有幫助。有些有同樣的錯誤 proxyconnect tcp: tls:first record does not Look like a TLS handshake 並解釋原因:

<code>
This is because the proxy answers with an plain HTTP error to the strange HTTP request (which is actually the start of the TLS handshake).
</code>

但是Steffen的回覆沒有範例程式碼如何設定DialContext func(ctx context.Context, network, addr string),Bogdan和cyberdelia都建議設定tls.Config{InsecureSkipVerify: true},例如這樣

<code>    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
    }
    client := &http.Client{Transport: tr}
</code>

但是上面的沒有效果。我仍然遇到同樣的錯誤。並且連接仍然調用 https://* 而不是 http://*

這是範例程式碼,我嘗試包含上述建議並對其進行調整:

<code>var tr = &http.Transport{ TLSClientConfig: 
                           &tls.Config{InsecureSkipVerify: true}, } 
                           // lacks DialContext config
var client*  http.Client = &http.Client{Transport: tr} // modified * added
// var client *http.Client // code from tutorial

type CatFact struct {
    Fact   string `json:"fact"`
    Length int    `json:"length"`
}

func GetCatFact() {
    url := "http://catfact.ninja/fact" // changed from https to http
    var catFact CatFact

    err := GetJson(url, &catFact)
    if err != nil {
        fmt.Printf("error getting cat fact: %s\n", err.Error())
    } else {
        fmt.Printf("A super interesting Cat Fact: %s\n", catFact.Fact)
    }
}

func main() {
    client = &http.Client{Timeout: 10 * time.Second}
    GetCatFact()
    // same error 
    // proxyconnect tcp: tls: first record does 
    //                   not look like a TLS handshake
    // still uses https 
    // for GET catfact.ninja
}
</code>

如何將連線配置為使用從 myClient 透過代理程式到伺服器的未加密連線?設定 DialContext func(ctx context.Context, network, addr string) 有助於做到這一點嗎?怎麼辦?

解決方法

我剛剛嘗試過:

package main

import (
    "context"
    "crypto/tls"
    "encoding/json"
    "fmt"
    "net"
    "net/http"
    "time"
)

type CatFact struct {
    Fact   string `json:"fact"`
    Length int    `json:"length"`
}

// Custom dialing function to handle connections
func customDialContext(ctx context.Context, network, addr string) (net.Conn, error) {
    conn, err := net.Dial(network, addr)
    return conn, err
}

// Function to get a cat fact
func GetCatFact(client *http.Client) {
    url := "https://catfact.ninja/fact"  // Reverted back to https
    var catFact CatFact

    err := GetJson(url, &catFact, client)
    if err != nil {
        fmt.Printf("error getting cat fact: %s\n", err.Error())
    } else {
        fmt.Printf("A super interesting Cat Fact: %s\n", catFact.Fact)
    }
}

// Function to send a GET request and decode the JSON response
func GetJson(url string, target interface{}, client *http.Client) error {
    resp, err := client.Get(url)
    if err != nil {
        return fmt.Errorf("error sending GET request: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return fmt.Errorf("received non-OK HTTP status: %d", resp.StatusCode)
    }

    err = json.NewDecoder(resp.Body).Decode(target)
    if err != nil {
        return fmt.Errorf("error decoding JSON response: %w", err)
    }

    return nil
}

func main() {
    // Create a custom Transport with the desired settings
    tr := &http.Transport{
        Proxy: http.ProxyFromEnvironment,  // Use the proxy settings from the environment
        DialContext: customDialContext,    // Use the custom dialing function
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,  // Skip certificate verification (not recommended in production)
        },
    }

    // Create a new HTTP client using the custom Transport
    client := &http.Client{
        Transport: tr,
        Timeout:   10 * time.Second,
    }

    // Call the function to get a cat fact
    GetCatFact(client)
}

它包括:

  • 自訂撥號函數customDialContext
    # 該函數目前是 net.Dial 的簡單包裝,但它提供了一個可以在必要時引入自訂撥號邏輯的位置。它用作自訂撥號功能,用於建立網路連線。

  • 傳輸設定:

    • 修改後的程式碼使用特定設定配置自訂 http.Transport,包括自訂撥號功能、環境中的代理設定以及跳過憑證驗證的 TLS 配置(用於測試)。
    • 原始程式碼也嘗試設定自訂http.Transport,但僅包含跳過憑證驗證的TLS配置,並沒有設定自訂撥號功能或代理設定。
  • 客戶端設定:

    • 修改後的程式碼使用自訂的 http.Transport 建立新的 http.Client,並設定逾時為 10 秒。
    • 原始程式碼也嘗試使用自訂http.Transport 建立新的http.Client ,但後來在main 函數中,它使用新的http.Client 覆寫了client 變量,其中包含預設的Transport 和逾時10秒的,有效丟棄自訂的Transport
  • 函數簽章:

    • 修改後的程式碼修改了GetCatFactGetJson 函數以接受*http.Client 參數,允許它們使用在main中建立的自訂http.Client
    • 原始程式碼沒有將 http.Client 傳遞給這些函數,因此它們將使用 net/http 套件提供的預設 http.Client
  • 網址:

    • 修改後的程式碼將 GetCatFact 函數中的 URL 恢復為“https://catfact.ninja/fact”,因為伺服器無論如何都會將 HTTP 請求重新導向到 HTTPS。
    • 原始程式碼已將 URL 變更為“http://catfact.ninja/fact”,以避免 TLS 握手錯誤。

上面提供的程式碼中的 customDialContext 函數不包含任何專門忽略 TLS 握手錯誤或將 TLS 握手更改為非 TLS 連線的邏輯。它只提供了自訂撥號功能,在提供的形式中,直接呼叫net.Dial,無需任何特殊處理。

忽略TLS憑證驗證錯誤的機制實際上是由http.Transport結構體的TLSClientConfig欄位提供的,具體是將InsecureSkipVerify欄位設定為true

tr := &http.Transport{
    TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}

该配置告诉 Go 跳过验证服务器的证书链和主机名,这是 TLS 握手过程的一部分。但是,它不会忽略其他类型的 TLS 握手错误或切换到非 TLS 连接。通常不建议在生产环境中使用 InsecureSkipVerify: true,因为它会禁用重要的安全检查。

如果您想强制使用非 TLS(纯 HTTP)连接,通常只需使用 http:// URL,而不是 https:// URL。但是,如果服务器或代理服务器将 HTTP 重定向到 HTTPS(例如 http://catfact.ninja/fact 的情况),则客户端将遵循重定向并切换到 TLS 连接。

以上是如何修復 proxyconnect tcp: tls: 第一筆記錄看起來不像 TLS 握手的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除