Golang中Gorilla Web Sockets实时通信无法正常工作的问题

Golang中Gorilla Web Sockets实时通信无法正常工作的问题 我从这里复制粘贴了一份示例代码。这段代码在我的本地计算机上可以直接运行。

image

但是当迁移到使用 Nginx 代理的 VPS 上时,它就失效了。由于这涉及到从 https://wss:// 的“转换”,我不清楚我哪里做错了。这是在线地址:https://ws.go4webdev.org

image

控制台给出了这个错误:

WebSocket 连接到 ‘wss://localhost:8080/echo’ 失败:

页面显示如下:

image

我怀疑是这一行出了问题,但我无法理解其语法。

//var addr = flag.String("addr", "127.0.0.1:8080", "http service address") <-- 在我的本地计算机上工作

var addr = flag.String("addr", "https://ws.go4webdev.org", "http service address") <-- 在 VPS 上失败

我的直觉告诉我这接近一个 CORS 错误,但我无法确认。

有什么线索能让我解决这个问题吗?


更多关于Golang中Gorilla Web Sockets实时通信无法正常工作的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

mje:

也许你需要 wss

是的,我需要 wss。

更多关于Golang中Gorilla Web Sockets实时通信无法正常工作的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我在想,既然这些按钮在表单内部,当你按下它们时,它们是否试图提交表单。尝试将这些按钮改为 button type="button",这样它们就不会提交表单并导致页面重新加载。

答案就在你的模板中:

homeTemplate.Execute(w, "ws://"+r.Host+"/echo")

你是否在反向代理或类似的东西后面运行这个程序?一个简单的解决办法是去掉模板的那部分,而将逻辑推送到浏览器端。像这样:

ws = new WebSocket("ws://" + document.location.host + "/echo");

尝试将这些按钮改为 button type="button",这样它们就不会提交表单并导致重新加载。

谢谢!我这样做了,并且又前进了一步 🙂

现在至少控制台显示了一个错误:

ws.js:21 WebSocket 连接到 ‘wss://ws.go4webdev.org/echo’ 失败:WebSocket 握手期间出错:意外的响应代码:400

有什么线索可以让我追踪这个问题吗?

我认为我找到了一个解决方案。WebSocket似乎是一个仅受HTTP 1.1支持的旧协议(这一点我无法确认)。但是,当在Nginx的sites-available配置中添加以下内容后,它似乎可以正常工作

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }

如果有人能确认这一点,我将不胜感激。

也许你需要使用 wss。我曾经有一个 WebSocket 项目,当部署在反向代理(nginx)后面时,需要通过 wss 访问。以下是几个代码片段:

// The websocket URL scheme. 
var wsScheme="{{.WSScheme}}";
...
  wsConn =  new WebSocket(wsScheme+"//" + wsUrl +"/socket");
	w.Header().Set("Content-Type", "text/html")

	t,err := template.ParseFiles("test.html")
	if err != nil {
		http.Error(w, fmt.Sprintf("parse file error: %s", err), http.StatusInternalServerError)
		return
	}

	var scheme struct {
		WSScheme string
	}
	if (!s.RunningLocal) {
		scheme.WSScheme="wss:"
	} else {
		scheme.WSScheme="ws:"
	}

	err = t.Execute(w, scheme)
	if err != nil {
		http.Error(w, fmt.Sprintf("template error: %s", err), http.StatusInternalServerError)
		return
	}

Dean_Davidson:

ws = new WebSocket("ws://" + document.location.host + "/echo");

谢谢,但是当把这个移到JavaScript中时,ws没有被赋值。我已经更新了JavaScript并添加了一些警告,这里是实时页面(仍然无法工作)。

在我看来,页面似乎被加载了两次,并且可能清除了ws的值?

window.addEventListener("load", function(evt) {
  alert("value of ws at load " + ws)
  var output = document.getElementById("output");
  var input = document.getElementById("input");
  var ws;
  var print = function(message) {
    var d = document.createElement("div");
    d.textContent = message;
    output.appendChild(d);
    output.scroll(0, output.scrollHeight);
  };

  document.getElementById("open").onclick = function(evt) {
    alert("value at ws at open: " + ws)

    if (typeof ws !== 'undefined' && ws !== null) {
      return
    }
    
    alert("assign value to ws")
    ws = new WebSocket("ws://" + document.location.host + "/echo");
    alert("ws://" + document.location.host + "/echo") // 由于某些原因,这行没有执行...
    alert(ws);

    ws.onopen = function(evt) {
      print("OPEN");
    }
    ws.onclose = function(evt) {
      print("CLOSE");
      ws = null;
    }
    ws.onmessage = function(evt) {
      print("RESPONSE: " + evt.data);
    }
    ws.onerror = function(evt) {
      print("ERROR: " + evt.data);
    }
    return false;
  };
  document.getElementById("send").onclick = function(evt) {
    if (!ws) {
      return false;
    }
    print("SEND: " + input.value);
    ws.send(input.value);
    return false;
  };
  document.getElementById("close").onclick = function(evt) {
    if (!ws) {
      return false;
    }
    ws.close();
    return false;
  };
});
回到顶部