【问题标题】:How to Connect Cowboy (Erlang) websocket to webflow.io generated webpage如何将 Cowboy (Erlang) websocket 连接到 webflow.io 生成的网页
【发布时间】:2025-12-10 05:45:01
【问题描述】:

我想使用牛仔 websocket 接口与使用 webflow 生成的网页进行交互。我想举一个简单的例子,如何添加实现连接到 webflow HTML 的 websocket 的 javascript。

【问题讨论】:

    标签: websocket erlang cowboy webflow


    【解决方案1】:

    这应该让你开始:

    1. Container(即div)拖到您的页面上。给它 ID server_info

    2. Button 拖到您的页面上。给它 ID get_server_info

    3. Page Settings 允许您使用add javascript to a pagejs for connecting to a server with a websocket 看起来像这样:

         <script>
          var ws = new WebSocket("ws://localhost:8080/please_upgrade_to_websocket");
      
          ws.onerror = function(event) {
              console.error("[ME]WebSocket error observed:", event);
          };
          ws.onclose = function(event) {
              console.log("[ME]WebSocket is closed now.");
          };
      
          $("#get_server_info").click(function() {
              if(ws.readyState == 1) {               
                  ws.send("My data");
              }
              else {
                  alert("Websocket not open! readyState: " + ws.readyState);
             }
          });
      
          ws.onmessage = function (event) {
              alert("Data was retrieved from server and will be inserted in page.");
              $("#server_info").text(event.data);
      
          };
      
         </script>
      
    4. Create a new cowboy app 调用了hello_erlang

    5. 通过将以下内容放入hello_erlang/src/hello_erlang_app.erl 中,创建一些路由并指定它们的处理函数:

       -module(hello_erlang_app).
       -behaviour(application).
      
       -export([start/2]).
       -export([stop/1]).
      
       start(_Type, _Args) ->
           HelloRoute = { "/", hello_handler, [] },
           WebSocketRoute = {"/please_upgrade_to_websocket", myws_handler, []},
           CatchallRoute = {"/[...]", no_matching_route_handler, []},
      
           Dispatch = cowboy_router:compile([
               {'_', [HelloRoute, WebSocketRoute, CatchallRoute]}
           ]),
      
      
           {ok, _} = cowboy:start_clear(my_http_listener,
               [{port, 8080}],
               #{env => #{dispatch => Dispatch} }
           ),
      
           hello_erlang_sup:start_link().
      
       stop(_State) ->
           ok.
      
    6. 为了提供带有按钮的简单 html 页面,我使用了hello_erlang/src/hello_handler.erl

       -module(hello_handler).
       -behavior(cowboy_handler).
      
       -export([init/2]).
      
       init(Req0, State) ->
           io:format("[ME]Entered hello_handler~n"),
           Body = my_get_file("html/form.htm"),  %% Body can be a binary() or an iolist() (which is a list containing integers, strings, or binaries)
           Req = cowboy_req:reply(200,
               #{<<"content-type">> => <<"text/html">>},
               Body,
               Req0),
      
           {ok, Req, State}.
      
       my_get_file(Path) ->
           PrivDir = code:priv_dir(hello_erlang),  %% Finds the path of an application's priv directory
           AbsPath = filename:join([PrivDir, Path]),
      
           case file:read_file(AbsPath) of 
               {ok, Bin} -> Bin;
               _  -> ["<div>Cannot read file: ", Path, "</div>"]  %% iolist()
           end.
      

    根据erlang docspriv 目录是应用程序特定文件所在的位置。下面是form.htm 页面,我把它放在了hello_erlang/priv/html/ 目录中(我创建了html 目录)。在 html 页面的 &lt;head&gt; 部分有一个 &lt;script&gt; 标记,它链接到 javascript 使用的 jquery 库:

    <!DOCTYPE html>
    <html>
      <head>
        <title>My Page</title>
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"   
                integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" 
                crossorigin="anonymous">
        </script>
      </head>
      <body>
        <div id="server_info">Server info</div>
        <button type="button" id="get_server_info">Get sever info</button>
    
        <script>
         var my_websocket = new WebSocket("ws://localhost:8080/please_upgrade_to_websocket");
    
         my_websocket.onerror = function(event) {
             console.error("[ME]WebSocket error observed:", event);
         };
         my_websocket.onclose = function(event) {
             console.log("[ME]WebSocket is closed now.");
         };
    
         $("#get_server_info").click(function() {
             if(my_websocket.readyState == 1) {               
                 my_websocket.send("My data");
             }
             else {
                 alert("Websocket not open! readyState: " + my_websocket.readyState );
            }
         });
    
         my_websocket.onmessage = function (event) {
             $("#server_info").text(event.data);
             alert("Data was retrieved from server and will be inserted in page.");
         };
    
        </script>
    
    
      </body>
    </html>
    

    编辑: 提供 html 文件的另一种方法是取消 hello_handler.erl 并像这样设置路由:

    HelloRoute = { "/", cowboy_static, {priv_file, hello_erlang, "html/form.htm"} },
    

    您可以将form.htm 放在目录hello_erlang/priv/html/ 中(我创建了html 目录)。请参阅static files 上的牛仔文档。当您在将 html 文件发送到客户端之前不需要使用 erlang 以某种方式更改 html 文件时,这是提供文件的最简单方法。

    1. hello_erlang/src/myws_handler.erl:

       -module(myws_handler).
       -export([init/2, websocket_init/1, websocket_handle/2, websocket_info/2]).
      
      
       init(Req, State) ->
           {cowboy_websocket, Req, State}.  %Perform websocket setup
      
       websocket_init(State) ->
           io:format("[ME]: Inside websocket_init()~n"),
           {ok, State}.
      
       websocket_handle({text, Msg}, State) ->
           {Hours, Minutes, Secs} = time(),
      
           {
                reply, 
                {text, io_lib:format("[~w:~w:~w]: Server received: ~s", [Hours, Minutes, Secs, Msg]) },
                State
           };
       websocket_handle(_Other, State) ->  %Ignore
           {ok, State}.
      
      
       websocket_info({text, Text}, State) ->
           {reply, {text, Text}, State};
       websocket_info(_Other, State) ->
           {ok, State}.
      
    2. hello_erlang/src/no_matching_route_handler.erl:

       -module(no_matching_route_handler).
       -behavior(cowboy_handler).
      
       -export([init/2]).
      
       init(Req0, State) -> %State comes from last argument of route
           Req = cowboy_req:reply(404,
               #{<<"content-type">> => <<"text/plain">>},
               <<"[ME] 404. Whoops! (No matching route!)">>,
               Req0),
           {ok, Req, State}.
      

    然后,在您的应用程序的*目录中,hello_erlang 在这种情况下,启动您的牛仔服务器:

    ...cowboy_apps/hello_erlang$ make run
    

    然后,在浏览器中输入以下网址:

    http://localhost:8080/
    

    这将导致cowboy 提供包含该按钮的html 页面。点击按钮会使用websocket向服务器发送一些数据,服务器会响应,然后js会在网页中插入响应。

    Webflow 确实与答案无关:无论您如何或使用什么来创建 html 和 javascript,最终产品都是一个 html 页面,您将其放在服务器目录的某个位置。当浏览器从您的服务器请求 html 文件时,服务器将 html 文件发送给浏览器,然后浏览器读取该文件并生成您看到的漂亮文本和图片,然后浏览器在适当的时间执行 javascript。浏览器不知道是谁在文件中创建了 html 和 javascript。

    【讨论】: