如何获取PureScript应用当前基础URL以动态构建WebSocket连接?
嘿,这个动态生成WebSocket连接地址的需求我之前也碰到过,在PureScript里有两种靠谱的实现方式,我给你详细讲讲:
方法1:通过浏览器Location API动态拼接
这种方式完全在前端处理,不需要后端改动,核心是利用浏览器的window.location对象获取当前页面的服务信息,再转换成WebSocket协议的地址。
代码实现
import Web.HTML (window) import Web.HTML.Location (Location, hostname, port, protocol) import Web.HTML.Window (location) import Effect (Effect) import Data.String (replace) -- 动态构建WebSocket连接地址 buildWsUrl :: Effect String buildWsUrl = do -- 获取当前窗口对象 win <- window -- 获取当前页面的location信息 loc <- location win -- 提取协议、主机名、端口 currentProto <- protocol loc currentHost <- hostname loc currentPort <- port loc -- 将http/https替换为ws/wss(自动适配加密连接) let wsProtocol = replace "http" "ws" currentProto -- 处理默认端口(80/443时浏览器不会显示端口,所以空字符串就不用加冒号) baseUrl = wsProtocol <> "//" <> currentHost <> (if currentPort == "" then "" else ":" <> currentPort) -- 拼接固定的WebSocket路径 pure $ baseUrl <> "/ws/blah"
使用示例
你可以在创建WebSocket连接的时候调用这个函数:
import Web.WebSocket.WebSocket (newWebSocket) import Effect.Class.Console (log) initWebSocket :: Effect Unit initWebSocket = do wsUrl <- buildWsUrl ws <- newWebSocket wsUrl log $"WebSocket连接地址:{wsUrl}" -- 这里可以添加onopen、onmessage等事件监听逻辑
方法2:后端注入全局变量(更推荐)
如果你的Suave后端可以控制前端页面的渲染,这种方式更可靠——后端直接根据当前运行环境生成正确的WebSocket地址,注入到页面的全局变量中,前端直接读取使用即可,避免前端拼接时可能出现的协议/端口错误。
后端(Suave)改动
在返回前端页面的模板中,添加一个全局变量:
open Suave open Suave.Html let getWsBaseUrl (ctx: HttpContext) = -- 根据当前环境配置生成WebSocket地址 let host = ctx.request.host let port = ctx.request.port |> Option.map string |> Option.defaultValue "" let portSuffix = if port = "" then "" else ":" + port $"ws://{host}{portSuffix}/ws/blah" let indexHandler (ctx: HttpContext) = let wsBaseUrl = getWsBaseUrl ctx html [ head [] body [ script [src "/output/bundle.js"] [] -- 注入全局变量 script [] [ text $"window.wsBaseUrl = \"{wsBaseUrl}\";" ] ] ] |> OK |> ctx |> run
前端(PureScript)读取
直接读取全局变量来创建WebSocket连接:
import Effect (Effect) import Web.HTML (window) import Data.Nullable (toMaybe) import Web.WebSocket.WebSocket (newWebSocket) import Effect.Class.Console (log) initWebSocket :: Effect Unit initWebSocket = do win <- window -- 读取后端注入的全局变量 let wsUrl = toMaybe (win ## wsBaseUrl) case wsUrl of Just url -> do ws <- newWebSocket url log $"已连接到WebSocket:{url}" -- 添加WebSocket事件监听 Nothing -> log "错误:未找到WebSocket连接地址"
注意事项
- 如果你的应用部署在HTTPS环境下,方法1中的
replace "http" "ws"会自动把https:转换成wss:,刚好适配加密的WebSocket连接,无需额外处理。 - 方法2的优势在于:当后端部署在反向代理后(比如Nginx),前端自己拼接可能会拿到代理的地址而非真实后端地址,后端注入的方式可以避免这个问题。
内容的提问来源于stack exchange,提问作者Sandoichi
相关产品推荐
相关产品推荐

