由于浏览器连接的是服务器上的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.引入依赖
org.springframework.boot
spring-boot-starter-websocket
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 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。很明显连接这里出现跨域了。
、
Stock Price
- {{ m.name }}: {{ m.price }}
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 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.测试