spring boot设置了Access-Control-Allow-Origin还是有跨域问题
最近使用spring cloud框架进行前后端分离开发,因为我们是通过网关去访问后台接口,ip
、端口都相同,所以没有出现过跨域问题,但是前端的同事把项目用webstrom打开以后(端口和ip就成了webstrom分配的)就有了跨域问题无法请求到后台,浏览器报"CORS 头缺少 'Access-Control-Allow-Origin'",但是我们已经在网关里设置了Access-Control-Allow-Origin为*,代码如下:
@Service
public class AuthFilter extends ZuulFilter {
/**
* 日志对象
*/
private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
@Autowired
private FilterConfig filterConfig;
/**
* redis缓存
*/
@Autowired
private RedisService redisService;
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
//解决浏览器跨域问题
response.addHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// response.addHeader("Access-Control-Allow-Credentials", "true");
// response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
// response.addHeader("Access-Control-Max-Age", "3600");
// response.addHeader("Vary", "Origin");
response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
//请求接口URL时登录token有效性校验
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
对此我在本地随便写了个小项目还原了当时的情景,我把代码以及报错贴出来麻烦各位看一下哪里有不对的;
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/jquery-1.9.1.min.js"></script>
</head>
<script>
function t1(){
$.ajax({
url:'http://localhost:9001/xzw/say',
type:'post',
contentType : 'application/json;charset=utf-8',
dataType:'json',
data : JSON.stringify({
batch_id : 'ncveirugheasolvgil'
}),
success : function(data){
alert('成功跨域');
alert(data);
},
error : function(){
alert('error');
}
})
}
</script>
<body>
<input type="button" value="测试跨域是否能获取数据" onclick="t1()"/>
</body>
</html>
后台代码:
@RestController
@RequestMapping("/xzw")
public class PageDemoController {
@RequestMapping("/say")
public String say(HttpServletRequest request,HttpServletResponse response,@RequestParam(value="batch_id")String batch_id){
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "*");
System.out.println("batch_id="+batch_id);
return "hello world";
}
}
浏览器报错
已拦截跨源请求:同源策略禁止读取位于 http://localhost:9001/xzw/say 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。[详细了解]
已拦截跨源请求:同源策略禁止读取位于 http://localhost:9001/xzw/say 的远程资源。(原因:CORS 请求未能成功)。[详细了解]
我们项目里的拦截器原本除了设置Access-Control-Allow-Origin还有验证token的代码,前端如果先进行登陆然后在ajax请求的时候把token拿到放在header里就不会有跨域问题,我把token验证的代码去掉了就出现了跨域问题,但是我看验证token的逻辑判断对跨域没有什么特殊的处理,一下为拦截器原代码:
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
//解决浏览器跨域问题
response.addHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// response.addHeader("Access-Control-Allow-Credentials", "true");
// response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
// response.addHeader("Access-Control-Max-Age", "3600");
// response.addHeader("Vary", "Origin");
response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
//请求接口URL时登录token有效性校验
Object token = request.getHeader("token");
if(token==null||token.equals("")) {
token = null;
}
boolean flag = false;//请求路径是否在过滤范围标识
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
ctx.setSendZuulResponse(false);
return null;
}
String ignores = filterConfig.getIgnores();
if(!StringUtilHelper.isEmpty(ignores)) {
String[] ignores_arr = ignores.split(",");
for(String ignore:ignores_arr) {
if(request.getRequestURI().toString().contains(ignore)) {
//无需token校验
flag = true;
break;
}
}
}
logger.info("网关日志:method={}, uri={},result={},token={}",request.getMethod(), request.getRequestURI(), (true==flag?"无需token校验":"需要token校验"),token);
if(!flag) {
//需要校验token有效性
if(token==null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
ctx.setResponseBody("token为空,未认证用户");
return null;
} else {
//redis校验
if(redisService.check(token.toString())!=ServiceConstants.STATE_1) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
ctx.setResponseBody("token超时,请重新登录");
return null;
}
}
}
return null;
}
在 你的AuthFilter 里面把shouldFilter() 替换成这个
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
if("OPTIONS".equals(request.getMethod())){
//过滤该请求,不往下级服务去转发请求,到此结束
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(200);
ctx.getResponse().setContentType("text/html;charset=UTF-8");
ctx.setResponseBody("true");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
return false;
}
return true;
}
是不是web.xml没有设置跨域访问的配置?例如
<!--跨域访问配置-->
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.allowOrigin</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.supportedHeaders</param-name>
<param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>
</init-param>
<init-param>
<param-name>cors.exposedHeaders</param-name>
<param-value>Set-Cookie</param-value>
</init-param>
<init-param>
<param-name>cors.supportsCredentials</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
跨域请求ajax的 把dataType的json换成jsonp。
请求的Origin属性设置有影响吗
解决跨域问题添加配置文件
/**
-
@Description: 解决跨域问题
/
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
@Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
//设置允许跨域的路径
registry.addMapping("/**")
//设置允许跨域请求的域名
.allowedOrigins("*")
//是否允许证书 不再默认开启
.allowCredentials(true)
//设置允许的方法
.allowedMethods("*")
//跨域允许时间
.maxAge(3600);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
试试这个吧。我们都是用这个就行了。
大家说的方法都是对的,我当时是请求头里没有带Access-Control-Allow-Headers里设置好的属性所以产生了无法跨域的情况,我随便算一个采纳了