Golang中WebSocket握手时遇到403错误如何解决

Golang中WebSocket握手时遇到403错误如何解决 code error

我正在尝试在Go和Angular中使用socket.io,但遇到了以下错误:

gin.SetMode(gin.ReleaseMode)
router := gin.Default()
//CORS
router.Use(cors.New(cors.Config{
AllowOrigins:     []string{"http://localhost:4200"},
AllowMethods:     []string{"PUT", "PATCH", "POST", "GET", "DELETE"},
AllowHeaders:     []string{"Origin", "X-Requested-With", "Content-Type", "Cache-
Control", "Pragma", "Authorization", "Accept", "Accept-Encoding"},
ExposeHeaders:    []string{"Content-Length"},
AllowCredentials: true,
// AllowOriginFunc: func(origin string) bool {
//  return origin == "*"
// },
MaxAge: 12 * time.Hour,
}))
server, err := socketio.NewServer(nil)
if err != nil {
log.Fatal(err)
}
server.OnConnect("/", func(s socketio.Conn) error {
s.SetContext("")
fmt.Println("connected:", s.ID())
return nil
})
server.OnEvent("/", "message", func(s socketio.Conn, msg string) {
fmt.Println("notice:", msg)
s.Emit("response", "Nuevo Pedido")
})
server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string {
s.SetContext(msg)
return "recv " + msg
})
server.OnDisconnect("/", func(s socketio.Conn, msg string) {
fmt.Println("closed", msg)
server.OnEvent("/", "bye", func(s socketio.Conn) string {
last := s.Context(https://bit.ly/2D5lSqU).(string)
server.OnDisconnect("/", func(s socketio.Conn, msg string) {
fmt.Println("closed", msg)
s.Emit("bye", last)
s.Close()
return last
})
server.OnDisconnect("/", func(s socketio.Conn, msg string) {
fmt.Println("closed", msg)
})
router.GET("/socket.io/*any", gin.WrapH(server))
router.POST("/socket.io/*any", gin.WrapH(server))
// router.Handle("WSS", "/socket.io", []gin.HandlerFunc{SocketHandler})
//SERVER PORT
router.Run(":5000")

更多关于Golang中WebSocket握手时遇到403错误如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中WebSocket握手时遇到403错误如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中使用socket.io库处理WebSocket连接时遇到403错误,通常是由于跨域(CORS)配置或握手验证问题导致的。以下是针对您代码的具体解决方案:

主要问题分析

403错误通常发生在WebSocket握手阶段,主要有以下几个原因:

  1. CORS配置不完整,缺少WebSocket相关头部
  2. socket.io服务器配置需要调整
  3. 握手验证失败

解决方案

1. 修复CORS配置,添加WebSocket相关头部

router.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"http://localhost:4200"},
    AllowMethods:     []string{"PUT", "PATCH", "POST", "GET", "DELETE", "OPTIONS"},
    AllowHeaders:     []string{
        "Origin", 
        "X-Requested-With", 
        "Content-Type", 
        "Cache-Control", 
        "Pragma", 
        "Authorization", 
        "Accept", 
        "Accept-Encoding",
        "Sec-WebSocket-Key",
        "Sec-WebSocket-Version",
        "Sec-WebSocket-Extensions",
        "Sec-WebSocket-Protocol",
        "Upgrade",
        "Connection",
    },
    ExposeHeaders:    []string{"Content-Length"},
    AllowCredentials: true,
    MaxAge: 12 * time.Hour,
}))

2. 配置socket.io服务器允许跨域

// 创建socket.io服务器时添加CORS配置
server, err := socketio.NewServer(&engineio.Options{
    Transports: []string{"websocket", "polling"},
    AllowUpgrades: []string{"websocket"},
    PingTimeout:  60000,
    PingInterval: 25000,
    Cors: &engineio.Cors{
        AllowOriginFunc: func(origin string) bool {
            return origin == "http://localhost:4200"
        },
        AllowCredentials: true,
    },
})
if err != nil {
    log.Fatal(err)
}

3. 添加OPTIONS方法处理预检请求

// 在路由中添加OPTIONS方法处理
router.OPTIONS("/socket.io/*any", func(c *gin.Context) {
    c.Header("Access-Control-Allow-Origin", "http://localhost:4200")
    c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
    c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
    c.Header("Access-Control-Allow-Credentials", "true")
    c.Status(200)
})

4. 完整修复后的代码示例

package main

import (
    "fmt"
    "log"
    "time"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
    socketio "github.com/googollee/go-socket.io"
    "github.com/googollee/go-socket.io/engineio"
)

func main() {
    gin.SetMode(gin.ReleaseMode)
    router := gin.Default()

    // CORS配置
    router.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"http://localhost:4200"},
        AllowMethods:     []string{"PUT", "PATCH", "POST", "GET", "DELETE", "OPTIONS"},
        AllowHeaders:     []string{
            "Origin",
            "X-Requested-With",
            "Content-Type",
            "Cache-Control",
            "Pragma",
            "Authorization",
            "Accept",
            "Accept-Encoding",
            "Sec-WebSocket-Key",
            "Sec-WebSocket-Version",
            "Sec-WebSocket-Extensions",
            "Sec-WebSocket-Protocol",
            "Upgrade",
            "Connection",
        },
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge: 12 * time.Hour,
    }))

    // 处理OPTIONS预检请求
    router.OPTIONS("/socket.io/*any", func(c *gin.Context) {
        c.Header("Access-Control-Allow-Origin", "http://localhost:4200")
        c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
        c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
        c.Header("Access-Control-Allow-Credentials", "true")
        c.Status(200)
    })

    // 创建socket.io服务器
    server, err := socketio.NewServer(&engineio.Options{
        Transports: []string{"websocket", "polling"},
        AllowUpgrades: []string{"websocket"},
        PingTimeout:  60000,
        PingInterval: 25000,
        Cors: &engineio.Cors{
            AllowOriginFunc: func(origin string) bool {
                return origin == "http://localhost:4200"
            },
            AllowCredentials: true,
        },
    })
    
    if err != nil {
        log.Fatal(err)
    }

    // 连接事件处理
    server.OnConnect("/", func(s socketio.Conn) error {
        s.SetContext("")
        fmt.Println("connected:", s.ID())
        return nil
    })

    server.OnEvent("/", "message", func(s socketio.Conn, msg string) {
        fmt.Println("notice:", msg)
        s.Emit("response", "Nuevo Pedido")
    })

    server.OnEvent("/chat", "msg", func(s socketio.Conn, msg string) string {
        s.SetContext(msg)
        return "recv " + msg
    })

    server.OnDisconnect("/", func(s socketio.Conn, msg string) {
        fmt.Println("closed", msg)
    })

    // 路由配置
    router.GET("/socket.io/*any", gin.WrapH(server))
    router.POST("/socket.io/*any", gin.WrapH(server))

    // 启动服务器
    fmt.Println("Server starting on :5000")
    router.Run(":5000")
}

5. Angular客户端连接示例

// 在Angular中连接时确保配置正确
import { io } from 'socket.io-client';

const socket = io('http://localhost:5000', {
  transports: ['websocket', 'polling'],
  withCredentials: true,
  extraHeaders: {
    "Authorization": "Bearer your-token-if-needed"
  }
});

socket.on('connect', () => {
  console.log('Connected to server');
});

socket.on('response', (data) => {
  console.log('Response:', data);
});

关键点说明

  1. CORS头部:必须包含WebSocket特定的头部(Sec-WebSocket-*等)
  2. OPTIONS预检:WebSocket握手前会发送OPTIONS请求,需要正确处理
  3. socket.io配置:需要在创建服务器时配置CORS选项
  4. 凭证传递:确保AllowCredentials: true和客户端withCredentials: true匹配

这些修改应该能解决您的403错误问题。如果问题仍然存在,请检查浏览器开发者工具的网络面板,查看具体的请求和响应头部信息。

回到顶部