java跨域解决思路及实现原理二

本文介绍了在Spring MVC框架中使用@CrossOrigin注解实现跨域访问的方法,并提供了通过自定义拦截器进行跨域设置的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我的上一篇文章讲了前端跨域的解决方案,这篇文章要讲的是java服务器端解决跨域。


先介绍一种最简单的解决方案:


springMVC的框架在4.2以上的版本就可以使用注解来实现跨域。我们并不需要去关注什么原理,直接拿来用就可以。
在我们的controller文件上添加@CrossOrigin注解,那么这个文件下的请求都支持跨域。如果要控制到某个请求被支持跨域,那么只要为该请求单独加上@CrossOrigin注解即可。
在@CrossOrigin注解里有一个叫“origins”的参数,设置这个参数就可以允许指定的服务器跨域。比如: @CrossOrigin(origins = "*")这样就表示允许所有跨域访问。


这里我仔细的讲一下,对于跨域其实就是修改了请求报头。下面的一些方法就是通过修改response的头文件来达到跨域效果。而@CrossOrigin注解也是去修改response的头文件来实现的。


有可能对于跨域上一篇的文章讲的还不是很清楚。我再重复一遍:跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。理解这一点是很重要的。


在开始下面的方法讲解之前了解一下response的头文件:
Access-Control-Allow-Origin:| * // 授权的源控制
Access-Control-Max-Age:// 授权的时间
Access-Control-Allow-Credentials: true | false // 控制是否开启与Ajax的Cookie提交方式
Access-Control-Allow-Methods:[,]* // 允许请求的HTTP Method
Access-Control-Allow-Headers:[,]* // 控制哪些header能发送真正的请求


注解以外的解决方案:


通过上面的讲解我们不难发现,所谓解决跨域就是要解决数据如何能够正确返回。这里我提供两种思路:一、继承的方式;二、拦截器的方式。


这里我比较推荐拦截器的方式,因为它不需要修改每个controller类。下面来看一下实现:
首先需要新建一个拦截器类,然后设置ressponse的头文件。下面来看具体代码:
public void doFilter(ServletRequest request, ServletResponse servletResponse,
            FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization");
response.setHeader("Access-Control-Allow-Credentials","true");
chain.doFilter(request, servletResponse);
}


拦截器实现了之后就需要在web.xml中配置,使拦截器发挥效果。下面是web.xml中的代码:
<filter>
     <filter-name>cors</filter-name>
     <filter-class>xxx.xxxx.HeadersCORSFilter</filter-class><!--过滤器路径-->
</filter>
<filter-mapping>
     <filter-name>cors</filter-name>
     <url-pattern>/url/*</url-pattern><!--接口前缀-->
</filter-mapping>


到这里使用拦截器的解决方案就完成了。至于继承的方式就是写一个公共的controller类,在该类中实现跨域,然后需要跨域的controller类继承该类就可以实现跨域了。


最后我再拓展一下浏览器cookie跨域。由于项目的原因,我的每次请求后台都会查看当前的cookie,如果没有登录成功时后台设置的cookie将会被拒绝访问。这样会带来一个问题,在另开页面访问时cookie无法共享导致请求失败。决解方法很简单就是在ajax请求时给xhrFields属性设置{ withCredentials: true }。完整的ajax请求代码展示:
$.ajax({
type:"post",
url:"url",
async:true,
xhrFields: { withCredentials: true },
data:,
dataType: "json",
success: function(result) {},
error: function(ret) {}
});


关于跨域的问题就讲这么多,谢谢。
<think>嗯,用户想通过Java和Vue.js使用SSE来实现AI会话功能。首先,我得确认SSE的基本概念和工作原理。SSE允许服务器单向推送数据到客户端,适合实时更新,比如聊天对话。用户提到的AI会话,可能涉及处理自然语言,可能需要集成像Dialogflow这样的服务,不过用户明确要求用Java和Vue,所以得考虑如何将这两部分结合起来。 接下来,我需要分步骤思考:首先,服务器端Java如何实现SSE。Java中可以使用Spring框架,特别是Spring WebFlux支持响应式编程,或者传统的Spring MVC。可能需要创建一个Controller,返回SseEmitter对象,这样客户端就能连接并接收事件流了。然后,处理AI响应,可能需要调用外部API,比如OpenAI或者自有的NLP服务,这里需要异步处理,避免阻塞SSE连接。 然后,Vue.js客户端如何建立SSE连接。需要使用EventSource API,监听服务器发送的消息,并更新前端界面。需要注意问题,确保Vue应用和Java后端在同一个,或者正确配置CORS。 另外,用户提供的引用中有提到Dialogflow和React.js的集成,但用户这里用Vue.js,可能需要类似的思路,比如在Java后端处理SSE的同时,调用Dialogflow的API来生成AI响应,然后通过SSE推送到前端。 还有,需要考虑错误处理和连接管理,比如客户端断开后如何重新连接,服务器端资源的释放等。Java的SseEmitter可能需要注册超时和完成回调,确保资源不被泄露。 最后,整合整个流程:用户在前端输入消息,通过SSE发送到Java后端,后端处理请求,调用AI服务,生成回复,再通过SSE推送到前端显示。可能需要处理消息的格式,比如JSON,确保前后端数据解析正确。 可能的问题包括SSE的连接稳定性,大数据量时的性能,以及如何维护多个并发的SSE连接。需要确保服务器端能够高效处理多个客户端连接,并且AI服务的响应时间在可接受范围内,避免延迟过高影响用户体验。</think>### 通过Java和Vue.js实现SSE驱动的AI会话功能 #### 一、核心实现步骤 1. **Java服务端实现SSE** ```java @RestController public class SseController { private final Map<String, SseEmitter> emitters = new ConcurrentHashMap<>(); @GetMapping("/sse/connect") public SseEmitter connect() { SseEmitter emitter = new SseEmitter(60_000L); emitters.put(UUID.randomUUID().toString(), emitter); emitter.onCompletion(() -> emitters.values().remove(emitter)); emitter.onTimeout(() -> emitters.values().remove(emitter)); return emitter; } @Async public void sendAIResponse(String sessionId, String message) { // 调用AI服务(示例) String aiResponse = callAIService(message); emitters.get(sessionId).send( SseEmitter.event() .data(aiResponse) .reconnectTime(3000) ); } } ``` *关键技术点:* - 使用Spring的`SseEmitter`实现事件推送 - 设置60秒超时和自动重连机制 - 异步处理AI响应(需要`@EnableAsync`配置) 2. **Vue.js客户端实现SSE连接** ```javascript // 组件内 data() { return { eventSource: null, messages: [] } }, mounted() { this.connectSSE(); }, methods: { connectSSE() { this.eventSource = new EventSource('http://localhost:8080/sse/connect'); this.eventSource.onmessage = (event) => { this.messages.push({ type: 'ai', content: event.data }); }; this.eventSource.onerror = (err) => { console.error('SSE error:', err); setTimeout(() => this.connectSSE(), 5000); }; }, sendMessage(message) { axios.post('/api/chat', { message }) .then(() => this.messages.push({ type: 'user', content: message })); } } ``` #### 、关键技术整合 1. **SSE与AI服务集成** - 使用`Apache HttpClient`调用第三方AI接口: ```java public String callAIService(String input) { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost post = new HttpPost("https://api.ai-service.com/chat"); post.setEntity(new StringEntity("{ \"text\": \"" + input + "\" }")); try (CloseableHttpResponse response = httpClient.execute(post)) { return EntityUtils.toString(response.getEntity()); } } } ``` 2. **消息协议设计** 建议使用JSON格式实现结构化数据传输: ```json { "type": "ai_response", "content": "你好!有什么可以帮您?", "timestamp": 1629264000000 } ``` #### 三、性能优化建议 1. 使用`WebFlux`实现响应式编程提升并发能力 2. 配置Nginx反向代理时增加: ```nginx proxy_set_header Connection ''; proxy_http_version 1.1; proxy_buffering off; proxy_cache off; ``` 3. 客户端实现心跳检测(每30秒发送ping包) #### 四、错误处理方案 1. **服务端重试策略** ```java emitter.send(SseEmitter.event() .data(response) .reconnectTime(5000) .retryDuration(15000)); ``` 2. **客户端错误恢复** ```javascript eventSource.onerror = () => { if (eventSource.readyState === EventSource.CLOSED) { console.log('Connection lost, reconnecting...'); setTimeout(connectSSE, 5000); } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值