如何从状态为 101 切换协议的响应中读取正文
Posted
技术标签:
【中文标题】如何从状态为 101 切换协议的响应中读取正文【英文标题】:How to read body from response with status 101 Switching Protocols 【发布时间】:2020-07-16 21:38:48 【问题描述】:我已连接到 Kubernetes 集群中的服务器,使用 POST 请求和标头来升级请求。我正在使用以下功能:
func PostRequest(client *http.Client, url string, bodyData []byte) (*http.Response, error)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(bodyData))
//req.Header.Set("Authorization", "Bearer " + BEARER_TOKEN)
req.Header.Set("X-Stream-Protocol-Version", "v2.channel.k8s.io")
req.Header.Set("X-Stream-Protocol-Version", "channel.k8s.io")
req.Header.Set("Upgrade", "SPDY/3.1")
req.Header.Set("Connection","upgrade")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := (*client).Do(req)
return resp, err
收到回复后,我尝试阅读,但阅读正文时卡住了:
url2 := "https://<serveri_ip>:10250/exec/default/mypod/mycontainer?command=ls&command=/&input=1&output=1&tty=1"
resp, err := PostRequest(api.GlobalClient, url2, []byte(""))
fmt.Println(r.Status)
fmt.Println(r.Header)
bodyBytes, err := ioutil.ReadAll(r.Body) // -> it stuck here
fmt.Println(string(bodyBytes))
我想它试图打开 websocket,所以我尝试像这样使用gorilla websocket library:
u := url.URLScheme: "ws", Host: "<node_ip>:10250", Path: "/exec/default/mypod/mycontainer?command=ls&command=/&input=1&output=1&tty=1"
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil
log.Fatal("dial:", err)
defer c.Close()
但它打印了一个错误:
2020/04/04 20:51:25 dial:websocket: 握手错误
我做错了什么? 如何从状态“切换协议”中读取响应正文
【问题讨论】:
关于使用 Gorilla 包。该错误表明服务器未使用 Web 套接字握手进行回复。端点可能由于多种原因导致握手失败:端点不支持协议、身份验证失败、重定向等。打印从 Dial 返回的响应以调试问题。此外,101 响应用于其他协议,例如 spdy 和 h2。 我认为这是因为端点正在使用 SPDY。所以我需要检查如何从 SPDY 协议中读取。我正在检查这个项目:github.com/amahi/spdy 我不确定您在这里期望什么。您正在执行升级请求 - 对此没有响应正文,但如果响应成功(即也是升级),您需要继续使用新协议。如果您不知道如何处理您请求的新协议(即 SPDY,而不是 Websockets 或其他),则不应请求它。 我不知道如何处理我需要的新协议。因为这就是端点的工作方式,所以他们正在使用 SPDY。所以我想了解如何使用这个协议来阅读它。试了上面写的SPDY库还是没有成功。 【参考方案1】:我设法用 Kubernetes go-client 库做到了:
package main
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"os"
"time"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
)
func main()
/*req.Header.Add("X-Stream-Protocol-Version", "v4.channel.k8s.io")
req.Header.Add("X-Stream-Protocol-Version", "v3.channel.k8s.io")
req.Header.Add("X-Stream-Protocol-Version", "v2.channel.k8s.io")
req.Header.Add("X-Stream-Protocol-Version", "channel.k8s.io")
req.Header.Add("Connection", "upgrade")
req.Header.Add("Upgrade", "SPDY/3.1")*/
//url2 := "https://123.123.123.123:10250/exec/default/my-pod/nginx?command=ls&command=/&input=1&output=1&tty=1"
tr := &http.Transport
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
TLSClientConfig: &tls.ConfigInsecureSkipVerify: true,
config := &restclient.Config
Host: "https://123.123.123.123:10250",
APIPath: "/exec/default/my-pod/nginx",
TLSClientConfig: restclient.TLSClientConfig
Insecure: true,
,
Transport: tr,
url3 := &url.URL
Scheme: "https",
Opaque: "",
User: nil,
Host: "123.123.123.123:10250",
Path: "/exec/default/my-pod/nginx",
RawPath: "",
RawQuery: "command=ls&command=/&input=1&output=1&tty=1",
exec, err := remotecommand.NewSPDYExecutor(config, "POST", url3)
if err != nil
fmt.Println(err)
// Thanks for this blog post https://www.henryxieblogs.com/2019/05/
err = exec.Stream(remotecommand.StreamOptions
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Tty:true,
)
fmt.Println(err)
【讨论】:
以上是关于如何从状态为 101 切换协议的响应中读取正文的主要内容,如果未能解决你的问题,请参考以下文章