You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Postman/Insomnia连接Erlang Websocket时出现解析错误

问题根源与解决方案

你遇到的问题本质是协议不匹配:

  • 你编写的是一个普通TCP echo服务器,仅处理原始二进制数据的收发
  • 但你用Postman/Insomnia的WebSocket客户端发起连接,WebSocket是基于HTTP握手的应用层协议,需要服务器先完成握手流程,你的TCP服务器完全没有处理这一步,导致客户端握手失败,触发「Parse Error: Expected HTTP/」,随后主动关闭连接,所以服务器端收到{error,closed}。

验证TCP服务器功能(如果仅测试TCP)

如果你的目标是测试这个TCP echo服务器,不要用WebSocket客户端,改用纯TCP客户端:

  • 使用telnet命令:telnet localhost 8091
  • 或者nc命令:nc localhost 8091
    输入任意内容,服务器会原样返回;输入包含quit的内容,连接会关闭,这完全符合代码预期。

实现WebSocket服务器的两种方式

如果需要支持WebSocket连接,有两种常见方案:

方案1:使用成熟的Erlang Web框架(推荐)

Erlang生态中最常用的是cowboy框架,它原生支持WebSocket。步骤大致如下:

  1. 添加cowboy依赖到你的项目(比如用rebar3)
  2. 编写WebSocket处理模块,示例代码:
-module(my_ws_handler).
-behaviour(cowboy_websocket_handler).

-export([init/3]).
-export([websocket_init/3]).
-export([websocket_handle/3]).
-export([websocket_info/3]).
-export([websocket_terminate/3]).

init({tcp, http}, _Req, _Opts) ->
    {upgrade, protocol, cowboy_websocket}.

websocket_init(_TransportName, Req, _Opts) ->
    {ok, Req, undefined_state}.

websocket_handle({text, <<"quit">>}, Req, State) ->
    {shutdown, Req, State};
websocket_handle({text, Msg}, Req, State) ->
    {reply, {text, Msg}, Req, State};
websocket_handle(_Data, Req, State) ->
    {ok, Req, State}.

websocket_info(_Info, Req, State) ->
    {ok, Req, State}.

websocket_terminate(_Reason, _Req, _State) ->
    ok.
  1. 配置并启动cowboy服务器,将WebSocket路由指向这个处理模块。

方案2:手动实现WebSocket握手(仅用于学习)

如果想手动处理WebSocket握手流程,需要解析客户端的HTTP请求,验证Upgrade头,生成符合规范的响应,然后切换到WebSocket帧协议。简化版的握手处理示例(仅处理基础握手,不支持子协议、扩展等):

handle_websocket_handshake(Socket) ->
    case gen_tcp:recv(Socket, 0) of
        {ok, Data} ->
            % 解析HTTP请求,提取Sec-WebSocket-Key
            case re:run(Data, "Sec-WebSocket-Key: (.*)\r\n", [{capture, [1], binary}]) of
                {match, [Key]} ->
                    % 生成握手响应
                    Accept = base64:encode(crypto:hash(sha, <<Key/binary, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11">>)),
                    Response = <<"HTTP/1.1 101 Switching Protocols\r\n",
                                "Upgrade: websocket\r\n",
                                "Connection: Upgrade\r\n",
                                "Sec-WebSocket-Accept: ", Accept/binary, "\r\n\r\n">>,
                    gen_tcp:send(Socket, Response),
                    % 握手完成后,开始处理WebSocket帧(需要解析帧格式)
                    handle_websocket_frames(Socket);
                _ ->
                    gen_tcp:close(Socket)
            end;
        _ ->
            gen_tcp:close(Socket)
    end.

handle_websocket_frames(Socket) ->
    % 这里需要实现WebSocket帧的解析和组装逻辑,比如处理文本帧、二进制帧等
    % 示例仅做简单接收(实际需要解析帧头)
    case gen_tcp:recv(Socket, 0) of
        {ok, _Frame} ->
            % 假设收到文本帧,返回相同内容(需要组装成WebSocket帧格式)
            gen_tcp:send(Socket, <<1:1, 0:3, 1:4, 0:1, 5:7, "hello">>), % 示例帧:文本帧,长度5,内容hello
            handle_websocket_frames(Socket);
        _ ->
            gen_tcp:close(Socket)
    end.

然后修改handle/1函数,先判断是否是WebSocket握手请求,再调用对应的处理函数。


内容的提问来源于stack exchange,提问作者Gradie Mayombe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 08:20:00