目前跨域有2种解决方案
1、jsonp:这种方式比较古老。 需要前后端配合 这里就不多说了 。 好处就是兼容老的浏览器
2、cors:这种方式是目前的主流。 CORS就是。。什么什么共享。 原理呢。就是服务器在response里面配置上各种允许。就好了。
cors又分2种
网上资料很多。我这里简单概述一下
1、简单请求:平常get、post(表单提交) 啥头信息都不加的情况 就是简单请求
2、复杂请求:如:post 传递 json形式的data 就是复杂请求
一、自定义Filter
之前api项目一直使用CorsFilter 。原理其实就是
写一个Filter在response中增加各种允许。 允许什么域名来访问,允许什么头信息之类的
public class CorsFilter implements Filter {
private String allowOrigin;
private String allowMethods;
private String allowCredentials;
private String allowHeaders;
private String exposeHeaders;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
allowOrigin = filterConfig.getInitParameter("allowOrigin");
allowMethods = filterConfig.getInitParameter("allowMethods");
allowCredentials = filterConfig.getInitParameter("allowCredentials");
allowHeaders = filterConfig.getInitParameter("allowHeaders");
exposeHeaders = filterConfig.getInitParameter("exposeHeaders");
System.out.println("allowOrigin = " + allowOrigin);
System.out.println("allowMethods = " + allowMethods);
System.out.println("allowCredentials = " + allowCredentials);
System.out.println("allowHeaders = " + allowHeaders);
System.out.println("exposeHeaders = " + exposeHeaders);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (StringUtil.isNotEmpty(allowOrigin)) {
List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
if (allowOriginList != null && allowOriginList.size() > 0) {
String currentOrigin = request.getHeader("Origin");
if (allowOriginList.contains(currentOrigin)) {
response.setHeader("Access-Control-Allow-Origin", currentOrigin);
}
}
}
if (StringUtil.isNotEmpty(allowMethods)) {
response.setHeader("Access-Control-Allow-Methods", allowMethods);
}
if (StringUtil.isNotEmpty(allowCredentials)) {
response.setHeader("Access-Control-Allow-Credentials", allowCredentials);
}
if (StringUtil.isNotEmpty(allowHeaders)) {
response.setHeader("Access-Control-Allow-Headers", allowHeaders);
}
if (StringUtil.isNotEmpty(exposeHeaders)) {
response.setHeader("Access-Control-Expose-Headers", exposeHeaders);
}
chain.doFilter(req, res);
}
@Override
public void destroy() {
}
}
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.yunxin.iambuyer.ucenter.filter.CorsFilter</filter-class>
<init-param>
<param-name>allowOrigin</param-name>
<param-value>http://XXX</param-value>
</init-param>
<init-param>
<param-name>allowMethods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
</init-param>
<init-param>
<param-name>allowCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>allowHeaders</param-name>
<param-value>Content-Type</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
二、springMVC自带的配置
在SpringMVC 配置文件中 增加
<!--cors跨域支持-->
<mvc:cors>
<mvc:mapping path="/**"
allowed-origins="http://127.0.0.1:8020,http://127.0.0.1:8081"
allowed-methods="GET,POST,PUT,DELETE,OPTIONS"
allowed-headers="Content-Type,token"
allow-credentials="true"
max-age="123" />
</mvc:cors>
需要注意的有一点
1、通常我们在项目中都有增加拦截器、过滤器。
在跨域首次会发送OPTIONS申请。如果这时候被过滤器拦截下来。并且返回业务的错误信息。会提示跨域。
这里是因为在这个错误信息返回的时候没有走springMVC配置的CORS跨域配置。 所以需要手动在返回的响应中。增加这个
比如我这个权限校验的过滤器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
String method = request.getMethod();
//options请求直接放行
if(method.equals("OPTIONS")){
return true;
}
//过滤不需要过滤接口
boolean isOver = RenderUtil.inContainURL(request, jwtProperties.getJwt_noAuthPath());
if (isOver) {
return true;
}
String msg = "请登录后再操作";
/*String content = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx582097e6b4749e25&redirect_uri=http%3A%2F%2Fapi.ruhexiu.com%2Frest-rp%2Fuser%2FwxLogin&response_type=code&scope=snsapi_userinfo&state=#wechat_redirect";*/
Map<String, String> map = new HashMap<>();
map.put("ret", "202");
map.put("msg", msg);
map.put("content",msg);
final String requestHeader = request.getHeader(jwtProperties.getJwt_header());
String authToken = null;
if (requestHeader != null && requestHeader.startsWith("Bearer ")) {
authToken = requestHeader.substring(7);
//验证token是否过期,包含了验证jwt是否正确
try {
boolean flag = jwtTokenUtil.isTokenExpired(authToken);
if (flag) {
RenderUtil.renderJson(response, map,request);
return false;
}
} catch (JwtException e) {
//有异常就是token解析失败
RenderUtil.renderJson(response, map,request);
return false;
}
} else {
//header没有带Bearer字段
RenderUtil.renderJson(response, map,request);
return false;
}
return true;
}
比如上面在
RenderUtil.renderJson(response, map,request);
这行代码的时候就会返回错误信息。所以在这个返回响应里面需要增加对CORS跨域的支持
/**
* 渲染json对象
*/
public static void renderJson(HttpServletResponse response, Object jsonObject,HttpServletRequest request) {
try {
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
//这里设置跨域
response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS");
response.setHeader("Access-Control-Allow-Headers","*");
response.setHeader("Access-Control-Allow-Credentials","true");
response.setHeader("Access-Control-Max-Age","123");
PrintWriter writer = response.getWriter();
writer.write(JSON.toJSONString(jsonObject));
} catch (IOException e) {
e.printStackTrace();
}
}
这样配置上springMVC提供的CORS配置。好使。
over~