通过 CROS 协议解决跨域问题
在前后端交互的开发中可能会遇到跨域的问题,如果只是简单的 GET 请求的话可以利用 Json 来解决。
对于非 GET 请求的话就可以采用 CORS
协议来解决了。CORS 是一个W3C标准,全称是"跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而解决了只能同源使用的限制,具体详解参考
跨域资源共享 CORS 详解。
如果你需要信息的绝对安全,不要依赖 CORS 当中的权限制度,应当使用更多其它的措施来保障,比如 OAuth2。
对于 Java 服务器的话,常用的解决方案就是自定义个 Filter 来添加相应头。
@Component
public class CorsFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(CorsFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort();
logger.info("orgin: {} request cors resource.", origin);
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");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
OPTIONS 是预请求必须允许。 Authorization 是做了 OAuth2 登录响应所必须的。 预请求在实际请求之前发出的请求,为了保证实际请求能够完成的权限请求,通过预请求的响应将能够确定实际请求是否的完成。
// 预请求
OPTIONS /cors HTTP/1.1
Origin: http://api.alice.com
// 实际请求类型
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header
Host: api.bob.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
// 预请求响应
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials(可选)- 表示是否允许cookies
Access-Control-Max-Age(可选) – 以秒为单位的缓存时间,允许时应当尽可能缓存。
Content-Type: text/html; charset=utf-8
<filter>
<filter-name>cors</filter-name>
<filter-class>CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
在 Spring 中提供了更为简单便捷的方法。
- 使用
@CrossOrigin
注解来设置跨域访问所允许的域名 - 继承
WebMvcConfigurerAdapter
设置跨域相关配置
@Component
public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter {
@Override public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*").allowedOrigins("*");
}
}
详细参考 Spring官方文档