vue、springboot集成websocket跨域问题解决
由于浏览器连接的是服务器上的websocket,导致出现了如下跨域错误: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'. Origin 'http://
由于浏览器连接的是服务器上的websocket,导致出现了如下跨域错误:
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'. Origin 'http://a.com' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute。
先分析下出现这个问题的原因:由于前后端分离导致我们通常会写跨域配置(如下代码)。但是报错很明显指出request's credentials mode is 'include',那么响应就the response must not be the wildcard '*’。所以直接配置Access-Control-Allow-Origin的值为通配是行不通的。具体怎么解决我接下来会讲。
package cn.datainvest.core.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 解决跨越配置类
* @author yangfeng
*
*/
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
/**
* 跨域过滤器
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
springboot集成websocket步骤如下:
1.引入依赖
<!--Websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2:WebSocketConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* @author yangfeng
**/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
}
}
3.业务代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class Weather {
@Resource
private IWeatherService weatherService;
private static Logger LOG = LoggerFactory.getLogger(WeatherScheduler.class);
@Autowired
private SimpMessagingTemplate messagingTemplate;
/**
* 保存天气信息
*/
public void saveWeather() {
ServiceResult<WeatherAO> serviceResult = weatherService.getWeatherAndSave();
if (serviceResult != null && serviceResult.isSucceed() && serviceResult.getData() != null) {
WeatherAO weather = serviceResult.getData();
//发送数据到webscoket
messagingTemplate.convertAndSend("/topic/weather", weather);
}
}
}
4.vue连接socket,开发环境访问地址:localhost:8089。很明显连接这里出现跨域了。
<template>
<div class="">、
<h1>Stock Price</h1>
<div>
<button @click="senMessage">发送消息</button>
<ul>
<li v-for="m in list1" :key="m.name">{{ m.name }}: {{ m.price }}</li>
</ul>
</div>
</div>
</template>
<script>
import SockJS from 'sockjs-client'
import Stomp from 'webstomp-client'
export default {
data() {
return {
list1: [],
stompClient: null
}
},
mounted() {
this.initWebSocket()
},
methods: {
senMessage() {
this.stompClient.send('/app/hello')
},
initWebSocket() {
this.connection()
// 需要有一个失败重连得到问题
},
connection() {
// 更换that指针
const socket = new SockJS('http://112.174.126.131:8080/websocket')
this.stompClient = Stomp.over(socket)
//建立连接,订阅主题
this.stompClient.connect({}, (frame) => {
console.log(frame)
this.stompClient.subscribe('/topic/terminalTrace', (val) => {
// this.list1 = JSON.parse(val.body)
console.log('-------++++++++++++++++++++++++++++++------------')
//下面会报错,应该是json的问题,但是数据可以接收到
console.log(val.body)
})
this.stompClient.subscribe('/topic/weather', (val) => {
// this.list1 = JSON.parse(val.body)
console.log('-------++++++++++++++++++++++++++++++------------')
//下面会报错,应该是json的问题,但是数据可以接收到
console.log(val.body)
})
})
// 回调函数 3 end
}
}
}
</script>
5.使用filter来解决
把之前写的跨域类CorsConfig 删除,加入下面的filter。
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Component
public class CorsFilter implements Filter {
// This is to be replaced with a list of domains allowed to access the server
//You can include more than one origin here
private final List<String> allowedOrigins = Arrays.asList("http://localhost:8089");
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
// Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Access-Control-Allow-Origin
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "*");
response.setHeader("Vary", "Origin");
// Access-Control-Max-Age
response.setHeader("Access-Control-Max-Age", "3600");
// Access-Control-Allow-Credentials
response.setHeader("Access-Control-Allow-Credentials", "true");
// Access-Control-Allow-Methods
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
// Access-Control-Allow-Headers
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");
}
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
}
加入origin的路径配置:
6.测试
更多推荐
所有评论(0)