什么是跨域
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
那么什么是同源策略
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
下面列出了一些常见跨域场景
针对跨域,目前有很多解决方案
1、 通过jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域资源共享(CORS)
7、 nginx代理跨域
8、 nodejs中间件代理跨域
9、 WebSocket协议跨域
下面我们就介绍一种目前主流的跨域解决方案——跨域资源共享(CORS)
什么是CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。IE8+:IE8/9需要使用XDomainRequest对象来支持CORS。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
后端配置
只需要配置一个过滤器即可,如下:
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
@Order(1)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
// 解决跨域问题
if (StringUtils.isNotEmpty(request.getHeader("Origin"))) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
} else {
response.setHeader("Access-Control-Allow-Origin", "*");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "36000");
response.setHeader("Access-Control-Allow-Headers", "accept,Access-Control-Request-Method,Access-Control-Request-Headers,Origin,token,x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
response.setHeader("Access-Control-Expose-Headers", "Content-Type, Authorization, credential, Content-Disposition");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
}
前端配置
前端配置只需要把withCredentials设置为true即可。
1.原生ajax
xhr.withCredentials = true;
2.vue框架
a.) axios设置:
// 前端设置是否带cookie
axios.defaults.withCredentials = true
b.) vue-resource设置:
Vue.http.options.credentials = true
这里假设后端服务地址为: 192.168.1.111:8080
我们需要配置一下hosts,(域名随便写)
192.168.1.111 server.google.com
这样访问 http://server.google.com:8080 也可能访问到你的后端服务了。
那么前端调用后端接口需要都写成 http://server.google.com:8080/+接口 这样的方式
访问前端也要用这种域名加端口的方式,比如本地启动了前端项目,端口是9090,那么也需要配置一下hosts,
127.0.0.1 front.google.com
就可以直接用 http://front.google.com:9090 访问前端页面了
也可以用下面这种配置方式直接设定vue启动后访问的url地址。
module.exports = {
dev: {
host: 'front.google.com', // can be overwritten by process.env.HOST
port: 80, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
...
}
}
总结一下
1、配置hosts
# 后端地址
192.168.1.111 server.google.com
# 前端地址
127.0.0.1 front.google.com
2、前端调用后端接口需要用域名+端口方式,例如 http://server.google.com:8080
3、在浏览器访问前端页面也需要用域名+端口的方式,例如 http://front.google.com
4、只要保证配置的两个域名的二级域名一样就可以了,三级域名随便。
5、这种方式只需要配置一次,如果想访问不同环境的后端服务,只需要修改hosts配置就可以了。而且部署前后端分离时,只需要修改前端调用后端接口的配置即可。
本文同步发在微信公众号上,感兴趣的可以关注一波