You need to enable JavaScript to run this app. 如何通过WebSocket消息发送换行指令?(FastAPI后端+React前端)
优惠活动
大模型
产品
解决方案
定价
更多

如何通过WebSocket消息发送换行指令?(FastAPI后端+React前端)

环境配置

  • Python FastApi 后端服务
  • JS React 前端客户端
  • 前端WebSocket客户端使用react-use-websocket库

问题描述

我需要通过WebSocket连接从后端API向前端客户端发送消息并向用户展示,但不知道如何在展示消息时实现换行效果。我尝试在WebSocket消息中发送\n,JS不会显示该\n字符但也不会触发换行,直接将其忽略;我也尝试发送多个空白字符,同样没有效果,无论我在API侧设置了多少空格,前端仅会展示单个空格。

代码示例

注:TextTransition组件来自react-text-transition库,该问题在标准HTML段落标签中也存在相同表现。

const {lastJsonMessage} = useWebSocket(socketURL);

//...

return (
    <div>
    ...
        ...
        <div style={boxStyle}>
            <h1 style={{cursor: "default"}}>Message</h1>
            <p style={{cursor: "default"}}>━━━━━━━━━━━━━━━━━</p>
            <TextTransition
                text={lastJsonMessage ? lastJsonMessage.message : ""}
                style={{cursor: "default"}}
                springConfig={ presets.stiff }
            />
        </div>
        ...
    ...
</div>
)

解决方案

该问题是HTML的默认渲染规则导致的:默认会把所有连续空白字符(换行符、制表符、多个空格)合并为单个空格,也不会将\n识别为换行标记,因此原生标签和第三方文本组件都会出现该现象。

方案1:添加CSS属性(最推荐,改动最小)

直接给展示文本的元素添加white-space: pre-wrap属性即可,该属性会保留文本中的换行符和连续空格,完全匹配你的需求,无需修改后端逻辑和数据结构。
修改后的代码如下:

<TextTransition
    text={lastJsonMessage ? lastJsonMessage.message : ""}
    style={{cursor: "default", whiteSpace: 'pre-wrap'}}
    springConfig={ presets.stiff }
/>

如果使用原生p标签展示,给p标签添加同样的style属性即可生效。

方案2:文本预处理后HTML渲染(适用于CSS方案不生效的场景)

如果TextTransition组件内部渲染逻辑不支持继承white-space属性,可以先对文本做转义处理后替换换行符为<br>标签,再用dangerouslySetInnerHTML渲染。注意如果消息内容包含用户生成内容,必须先做XSS转义避免安全风险。
代码示例:

// 文本格式化方法
const formatMessage = (msg) => {
  if (!msg) return ""
  // 先转义HTML特殊字符
  const escaped = msg.replace(/&/g, "&amp;")
                     .replace(/</g, "&lt;")
                     .replace(/>/g, "&gt;")
  // 替换换行符为br标签
  return escaped.replace(/\n/g, "<br />")
}

// 渲染部分
<TextTransition
    style={{cursor: "default"}}
    springConfig={ presets.stiff }
>
    <div dangerouslySetInnerHTML={{__html: formatMessage(lastJsonMessage?.message)}} />
</TextTransition>

方案3:逐行分割渲染

如果不想使用dangerouslySetInnerHTML,可以把文本按\n分割为数组,遍历渲染每一行内容,同时配合white-space: pre-wrap保留连续空格:

const messageLines = lastJsonMessage?.message?.split('\n') || []

// 渲染部分
<TextTransition
    style={{cursor: "default", whiteSpace: 'pre-wrap'}}
    springConfig={ presets.stiff }
>
    {messageLines.map((line, idx) => <div key={idx}>{line}</div>)}
</TextTransition>

内容的提问来源于stack exchange,提问作者Alperen Ozturk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.22 01:54:02