SSE实时通信与前端联调实战

1.SSE 原理机制

sse 类似websocket,但是sse是单向的,不可逆的,只能服务端向客户端发送数据流

2.解决跨域问题

Access to XMLHttpRequest at 'http://127.0.0.1:8090/sse/doChat' from origin 'http://127.0.0.1:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
request.js:48err: Error: Network Error 

require.js 文件


// 创建axios实例
const instance = axios.create({// baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url// baseURL: "http://192.168.3.110:8090", // url = base url + request urlbaseURL: "http://127.0.0.1:8090", // url = base url + request url// baseURL: "http://150.109.247.64:9090",// baseURL: "https://www.itzixi.com/api", // url = base url + request urlwithCredentials: true, // send cookies when cross-domain requeststimeout: 60000 // request timeout
});// axios请求的拦截器
instance.interceptors.request.use(config => {// do something before request is sentvar userInfo = cookieUtils.getUserInfo();// console.log(userInfo);if (userInfo) {// console.log("userId = " + userInfo.id);config.headers['headerUserId'] = userInfo.id;}var userToken = cookieUtils.getToken();// console.log("userToken = " + userToken);if (userToken) {// console.log("userToken = " + userToken);config.headers['headerUserToken'] = userToken;}return config},error => {// do something with request errorconsole.log(error) // for debugreturn Promise.reject(error)}
);// axios响应的拦截器
instance.interceptors.response.use(response => {const res = response.datareturn res;},error => {console.log('err: ' + error) // for debugconsole.log('err: ' + error.data) // for debugreturn Promise.reject(error)}
)
MvcConfiguration.java 文件如下
package com.spring.springai.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class MvcConfiguration implements WebMvcConfigurer {/*** 解决跨域* addMapping:设置哪些接口支持跨域* allowedOrigins:设置跨域的来源,也就是哪些域名最终可以接收响应* allowedMethods:设置支持跨域的方法* allowHeaders:运行哪些请求头* @param registry*/public void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允许所有接口支持跨域.allowedOrigins("*")// 允许所有来源.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")// 允许所有HTTP方法.allowedHeaders("*");// 允许所有请求头
//         .allowCredentials(true); // 允许发送Cookie,需要指定具体的origin}
}

这个错误是因为你的前端请求设置了 withCredentials: true(即包含凭据,如 cookies、HTTP认证等),但后端 CORS 配置使用了通配符 * 作为 allowedOrigins,这是不被允许的。

根据 CORS 策略,当请求包含凭据时,服务器不能使用 Access-Control-Allow-Origin: *,而必须指定明确的域名。

你有两种解决方案:

方案1:前端移除 withCredentials(如果不需凭据)

如果你的跨域请求不需要携带 cookies 或认证信息,可以在前端代码中移除 withCredentials 设置:

// 如果是使用 axios
axios.get('http://127.0.0.1:8090/sse/doChat', {withCredentials: false // 或者直接移除这个配置
})// 如果是原生 XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.withCredentials = false; // 设置为 false
方案2:后端指定具体域名并启用 allowCredentials(推荐)

如果你需要携带凭据,修改后端的 CORS 配置:

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://127.0.0.1:3000") // 指定前端具体域名.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").allowCredentials(true); // 允许凭据}
}
方案3:使用 allowedOriginPatterns(更灵活)

Spring Framework 5.3+ 支持使用模式匹配:

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("http://127.0.0.1:*", "http://localhost:*") // 使用模式匹配.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").allowCredentials(true);}
}
方案4:使用 Filter 进行更精细的控制
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true);config.addAllowedOrigin("http://127.0.0.1:3000");config.addAllowedHeader("*");config.addAllowedMethod("*");source.registerCorsConfiguration("/**", config);return new CorsFilter(source);}
}
对于 SSE (Server-Sent Events) 的特殊处理

如果你使用的是 SSE,还需要确保正确处理 OPTIONS 预检请求:

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/sse/**") // 单独配置 SSE 端点.allowedOrigins("http://127.0.0.1:3000").allowedMethods("GET", "POST", "OPTIONS").allowedHeaders("*").allowCredentials(true).maxAge(3600); // 预检请求缓存时间}
}

推荐使用方案2或方案3,指定具体的前端域名并启用 allowCredentials(true),这样既能保证安全性,又能满足携带凭据的需求。

最终解决方法:
  public void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**") // 允许所有接口支持跨域//.allowedOrigins("*")// 允许所有来源.allowedOrigins("http://127.0.0.1:3000", "http://localhost:3000", "http://ai.mywoshop.com:3000").allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")// 允许所有HTTP方法.allowedHeaders("*")// 允许所有请求头.allowCredentials(true); // 允许发送Cookie,需要指定具体的origin}

前端代码:https://gitee.com/yang-jiayu12/springai-mcp-front-end

后端代码:https://gitee.com/yang-jiayu12/springai-mcp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/920328.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920328.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从传统到创新:用报表插件重塑数据分析平台

一、传统 BI 平台面临的挑战 在当今数字化时代,数据已成为企业决策的重要依据。传统的商业智能(BI)平台在数据处理和分析方面发挥了重要作用,但随着数据量的爆炸式增长和用户需求的日益多样化,其局限性也逐渐显现。 …

MySQL--MySQL中的DECIMAL 与 Java中的BigDecimal

1. 为什么需要 DECIMAL在数据库中,常见的数值类型有:INT、BIGINT → 整数,存储容量有限。FLOAT、DOUBLE → 浮点数,存储效率高,但存在精度丢失问题。DECIMAL(M, D) → 定点数,存储精确值。例子:…

低空无人机系统关键技术与应用前景:SmartMediaKit视频链路的基石价值

引言:低空经济的新兴格局 低空经济作为“新质生产力”的代表,正在从政策驱动、技术突破和市场需求的共振中走向产业化。2023年,中国低空经济的市场规模已超过 5000 亿元人民币,同比增长超过 30%。无人机(UAV&#xff…

在Windows系统上升级Node.js和npm

在Windows系统上升级Node.js和npm,我推荐以下几种方法: 方法1:使用官网安装包(最简单) 访问 nodejs.org 下载Windows安装包(.msi文件) 运行安装包,选择"修复"或直接安装新…

【Jetson】基于llama.cpp部署gpt-oss-20b(推理与GUI交互)

前言 本文在jetson设备上使用llama.cpp完成gpt-oss 20b的部署,包括后端推理和GUI的可视化交互。 使用的设备为orin nx 16g(super),这个显存大小推理20b的模型完全没有问题。 使用硬件如下,支持开启super模式。&#…

Matplotlib 可视化大师系列(一):plt.plot() - 绘制折线图的利刃

目录Matplotlib 可视化大师系列博客总览Matplotlib 可视化大师系列(一):plt.plot() - 绘制折线图的利刃一、 plt.plot() 是什么?二、 函数原型与核心参数核心参数详解三、 从入门到精通:代码示例示例 1:最基…

第二阶段Winfrom-8:特性和反射,加密和解密,单例模式

1_预处理指令 (1)源代码指定了程序的定义,预处理指令(preprocessor directive)指示编译器如何处理源代码。例如,在某些情况下,我们希望编译器能够忽略一部分代码,而在其他情况下&am…

【开题答辩全过程】以 微信小程序的医院挂号预约系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

鸿蒙ArkUI 基础篇-06-组件基础语法-Column/Row/Text

目录 掌握组件写法,使用组件布局界面 ArkUI与组件 先布局再内容 DevEco Studio代码实战 预览效果 总结 练习 掌握组件写法,使用组件布局界面 ArkUI与组件 ArkUI(方舟开发框架):构建 鸿蒙 应用 界面 的框架 组件…

8.27 网格memo

lc329计算矩阵中最长递增路径长度尝试从矩阵每个位置出发,int dfs() 往上下左右四个方向找严格递增的路径retmax(ret,dfs(x,y)1);return memo[i][j]ret;返回所有路径里的最长长度 class Solution {public:int dx[4]{0,0,1,-1};int dy[4]{1,-1,0,0};int m,n;vector&l…

flume监控文件写入 Kafka 实战:解耦应用与消息队列的最佳实践

flume监控文件写入 Kafka 实战:解耦应用与消息队列的最佳实践 在日志采集场景中,直接让应用程序通过 log4j2 写入 Kafka 会导致应用与 Kafka 强耦合(如 Kafka 故障可能影响应用运行)。更优的方案是:应用程序将日志写入…

从浏览器无法访问到Docker容器的 FastAPI 服务地址【宿主机浏览器和容器不在同一个网络层面:端口映射】

文章目录1. 问题根源:Docker 网络模型2. 解决方案:端口映射(Port Mapping)方法 1:重新运行容器并添加端口映射(推荐)方法 2:获取宿主机的 IP 进行访问(特定情况&#xff…

线性代数中矩阵等价与离散数学中关系的闭包之间的关联

最近在重温线性代数时,学到矩阵的等价的定义及其性质,发现其性质与离散数学中关系的闭包所要满足的性质非常相似,不由的让人不怀疑这二者之间存在某种关联,从而引发以下的思考:从deepseek的回答中我明白了矩阵的等价其…

从MyJUnit反思Java项目的工程实践(版本控制篇)

从 MyJUnit 反思Java项目的工程实践(版本控制篇) 参考资料 deepseekgithub copilotCSDN-Git代码管理工作流程:GitFlow详解Conventional Commits手册封面来自 qwen-image 遵循 git flow 分支管理模型 Git Flow 是一种围绕项目发布的核心分支模型, 它规定了不同的开发…

小工具推荐

小工具 ​ 平时不太喜欢去搜罗一些好用的工具,但是看到自己感兴趣的还是会记下来,有的是github上的开源项目,有的是一些直接在线的工具。主要是除了工作时间也不知道去干点什么,或者是和朋友玩玩游戏,或者是city walk…

【js】加密库sha.js 严重漏洞速查

前言sha.js 是 JavaScript 生态里最常用的轻量级加密库。它由 Browserify 社区维护,体积不足 20 KB,却实现了 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 全系列算法,是 crypto-browserify、webpack、web3.js 等数百个流行包的“根依赖”。而…

FPGA入门学习路径

FPGA入门学习路径 专业基础 数电(数字电路基础-CSDN博客) 语法 Verilog(Verilog硬件描述语言-CSDN博客) VHDL(VHDL硬件描述语言-CSDN博客) FPGA开发流程 常用接口设计 学习目的:通过简单…

HTML响应式设计的颜色选择器,适配各种屏幕尺寸

颜色选择器 响应式设计的颜色选择器,适配各种屏幕尺寸 支持色相滑块和RGB数值两种调色方式 点击颜色值或复制按钮即可复制十六进制颜色代码 自动根据背景色调整文字颜色确保可读性 包含复制成功提示动画效果 现代化UI设计,采用圆角、阴影和渐变背景 完全…

ChatGPT登录不进怎么办?

ChatGPT登录不进的核心原因分类ChatGPT登录失败并非单一问题导致,通常与网络环境、账号状态、设备设置及平台限制相关,不同场景下的故障表现与诱因存在明显差异,可分为以下四类:网络连接与地域限制:ChatGPT对访问地域有…

【ConcurrentHashMap】实现原理和HashMap、Redis哈希的区别

【ConcurrentHashMap】实现原理和HashMap、Redis哈希的区别【一】核心思想【1】HashMap​(1)概括(2)🚀线程不安全的场景和原因1-场景一:Put 操作导致的数据覆盖/丢失 (Lost Update)​​2-场景二&#xff1a…