
本教程旨在解决go语言websocket服务器在处理客户端连接时常见的403 forbidden错误,该问题通常源于go.net/websocket包默认的origin头部校验机制。文章将深入解释错误原因,并提供使用websocket.server进行灵活配置的解决方案,确保服务器能够正确响应各类websocket客户端请求,构建稳定可靠的websocket服务。
在Go语言中搭建WebSocket服务器,通常会利用code.google.com/p/go.net/websocket包(请注意,此包为早期版本,生产环境建议考虑github.com/gorilla/websocket或net/http的升级功能)。一个简单的WebSocket Echo服务器可以接收客户端发送的消息并回传。以下是一个基础的实现示例:
package main
import (
"fmt"
"code.google.com/p/go.net/websocket"
"net/http"
)
// webHandler 处理WebSocket连接,接收并打印消息,然后回传
func webHandler(ws *websocket.Conn) {
var s string
// 从WebSocket连接读取数据
if _, err := fmt.Fscan(ws, &s); err != nil {
fmt.Printf("Error reading from websocket: %v\n", err)
return
}
fmt.Println("Received: ", s)
// 将消息回传给客户端
if _, err := fmt.Fprint(ws, "Echo: "+s); err != nil {
fmt.Printf("Error writing to websocket: %v\n", err)
}
}
func main() {
fmt.Println("Starting WebSocket server on :8080")
// 使用websocket.Handler注册WebSocket处理函数
// 默认情况下,websocket.Handler会执行Origin头部校验
http.Handle("/echo", websocket.Handler(webHandler))
// 启动HTTP服务器监听
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}配套的JavaScript客户端连接代码如下:
// 创建WebSocket连接
ws = new WebSocket("ws://localhost:8080/echo");
// 连接成功时触发
ws.onopen = function(event) {
console.log("WebSocket connection opened.");
// 连接建立后发送一条消息
ws.send("Hello from client!");
};
// 收到服务器消息时触发
ws.onmessage = function(e) {
console.log("WebSocket message received: " + e.data);
};
// 连接发生错误时触发
ws.onerror = function(error) {
console.error("WebSocket error: ", error);
};
// 连接关闭时触发
ws.onclose = function(event) {
console.log("WebSocket connection closed:", event.code, event.reason);
};然而,当尝试使用上述配置的Go服务器与JavaScript客户端连接时,可能会在浏览器控制台看到类似WebSocket connection to 'ws://localhost:8080/echo' failed: Unexpected response code: 403的错误信息。
这个403 Forbidden错误并非表示认证失败,而是与code.google.com/p/go.net/websocket包内部的Origin头部校验机制密切相关。websocket.Handler在默认情况下,会检查HTTP请求中的Origin头部是否是一个有效的URL。
立即学习“go语言免费学习笔记(深入)”;
Origin头部是Web浏览器在发起跨域请求(包括WebSocket连接)时自动添加的一个安全特性,它指示了请求发起的源(协议、域名和端口)。websocket.Handler默认会验证这个Origin头部,如果出现以下情况,它可能会拒绝连接:
在上述任何一种情况下,websocket.Handler都会拒绝连接,并返回403状态码。这对于Web浏览器客户端而言是一种重要的安全保障,可以防止恶意网站发起WebSocket连接。然而,对于需要连接非浏览器客户端(如桌面应用、移动应用或服务器间通信)或在特定开发场景下,这种默认的严格校验可能会造成困扰。
为了解决Origin校验导致的403错误,我们需要更精细地控制WebSocket连接的握手过程。code.google.com/p/go.net/websocket包提供了websocket.Server结构体,它允许我们自定义握手逻辑,特别是对Origin头部的处理。
通过websocket.Server,我们可以选择禁用默认的Origin校验,或者实现自定义的校验逻辑。对于需要接受非浏览器客户端或Origin头部可能不符合默认校验规则的场景,使用websocket.Server是更灵活且强大的选择。
以下是修改后的Go服务器代码,它使用websocket.Server来处理WebSocket连接,从而绕过默认的Origin校验:
package main
import (
"fmt"
"code.google.com/p/go.net/websocket"
"net/http"
)
// webHandler 保持不变,处理WebSocket连接的业务逻辑
func webHandler(ws *websocket.Conn) {
var s string
if _, err := fmt.Fscan(ws, &s); err != nil {
fmt.Printf("Error reading from websocket: %v\n", err)
return
}
fmt.Println("Received: ", s)
// 示例:回传消息
if _, err := fmt.Fprint(ws, "Echo: "+s); err != nil {
fmt.Printf("Error writing to websocket: %v\n", err)
}
}
func main() {
fmt.Println("Starting WebSocket server on :8080 with custom Origin handling")
// 使用http.HandleFunc注册一个普通的HTTP处理函数
// 在这个处理函数内部,我们创建并使用websocket.Server实例
http.HandleFunc("/echo",
func (w http.ResponseWriter, req *http.Request) {
// 创建websocket.Server实例
// 将webHandler作为其Handler。
// 关键点:当websocket.Server的Handshake字段为nil时,它不会执行Origin校验,
// 而是接受所有连接。这与websocket.Handler的默认行为不同。
s := websocket.Server{Handler: websocket.Handler(webHandler)}
// 调用ServeHTTP来处理当前的HTTP请求,将其升级为WebSocket连接
s.ServeHTTP(w, req)
})
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}通过这种方式,websocket.Server在处理请求时,如果其Handshake字段为nil,它将不会执行默认的Origin校验,从而允许各种客户端(包括那些不发送Origin头部或发送不符合默认校验规则Origin头部的客户端)成功建立WebSocket连接。
通过理解go.net/websocket包中Origin校验的机制,并恰当地利用websocket.Server,我们可以灵活地构建Go语言WebSocket服务器,以适应不同类型的客户端连接需求,避免常见的403错误,并根据实际场景平衡安全性和便利性。
以上就是Go语言WebSocket服务器:解决403 Origin校验错误与灵活配置的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号