一. 什么是跨域:
域名地址的组成:
http:// www . google : 8080 / script/jquery.js
1. http:// (协议号)
2. www (子域名)
3. google (主域名)
4. 8080 (端口号)
script/jquery.js (请求的地址)
* 当协议、子域名、主域名、端口号中任意一各不相同时,都算不同的“域”。
* 不同的域之间相互请求资源,就叫“跨域”。
比如:http://www.abc.com/index.html 请求 http://www.def.com/sever.php
同源策略
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
二. 处理跨域的方法
1. JSONP
JSONP 跨域请求, 可以参考我这篇博客 Jsonp 跨域 处理
2. 响应头中设置 Access-Control-Allow-Origin
//如果是普通的前端跨域请求的话, 就直接在后端返回参数时设置响应头就可以了 response.setHeader("Access-Control-Allow-Origin", "*");
3. CORS 跨域(OPTIONS)
浏览器会在发送真正请求之前,先发送一个方法为OPTIONS的预检请求 Preflighted requests
这个请求是用来验证本次请求是否安全的,而且并不是所有请求都会发送,需要符合以下条件:
- 请求方法不是GET/HEAD/POST
- POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain
- 请求设置了自定义的header字段
对于管理端的接口,我有对接口进行权限校验,每次请求需要在header中携带自定义的字段(token),所以浏览器会多发送一个OPTIONS请求。
那为什么OPTIONS请求报错了。。。
经过debug发现,OPTIONS请求只会携带自定义的字段,并不会将相应的值带入进去,而后台校验token字段时 token为NULL
,所以验证不通过,抛出了一个异常。
解决
先在项目中加个过滤器 Filter.import org.springframework.stereotype.Component; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class OriginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; HttpServletRequest httpRequest = (HttpServletRequest) request; httpResponse.setHeader("Access-Control-Allow-Origin", httpRequest.getHeader("Origin")); httpResponse.setHeader("Access-Control-Allow-Methods", httpRequest.getMethod()); httpResponse.setHeader("Access-Control-Max-Age", "3600"); httpResponse.setHeader("Access-Control-Allow-Headers", httpRequest.getHeader("Access-Control-Request-Headers")); chain.doFilter(request, response); } @Override public void destroy() { } }
if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return true; }
实际代码根据实际项目, 实际需求来, 但是原理是一样的. 可以根据原理来写相对应的代码
CORS 详解可以 去查看,参考这篇博客 跨域资源共享 CORS 详解
4. 代理
比如在北京(www.beijing.com/sever.php)和上海(www.shanghai.com/sever.php)各有一个服务器,北京的后端(www.beijing.com/sever.php)直接访问上海的服务,然后把获取的响应值返回给前端。也就是北京的服务在后台做了一个代理,前端只需要访问北京的服务器也就相当与访问了上海的服务器