Web跨域问题解决
程序员文章站
2022-05-03 12:50:09
...
hello, i'm Shendi
当我们项目前后端分离后,使用ajax就会遇到跨域问题
在解决问题之前,我们先来了解一下什么是跨域
什么是跨域?
w3c的标准,CORS 跨域资源共享(Cross-origin resource sharing)
简单地说就是当前网站只允许请求自己的域的资源,而对其他域的资源不信任
那么,什么情况才算跨域呢?
- 协议不同(http/https)
- 域名/ip不同(www.baidu.com 和 m.baidu.com 就是跨域)
- 端口不同
针对于Cookie,Ajax等,页面引入资源一般是不会有跨域问题的
对于Cookie跨域无法获取可以通过给Cookie设置domain来解决
分为简单请求与复杂请求
请求类型为 get/post/head则是简单请求,其余都是复杂请求
简单请求
当我们跨域请求时,浏览器会带请求头 Origin 请求服务器,Origin的值为当前网站地址/域名(域)
这时,服务器需要给响应添加响应头
// 当前服务器允许跨域的地址,可为*
Access-Control-Allow-Origin: 地址
//是否允许后续请求携带认证信息,该值只能是true,否则不返回
Access-Control-Allow-Credentials: true
浏览器接收到响应后会通过Access-Control-Allow-Origin判断与当前域是否一致,如果不一致就出现了跨域错误了
复杂请求
浏览器会先发送 option 预检请求,不过有时候并没有(缓存)
与简单请求不同的是,option 请求多了2个字段
Access-Control-Request-Method: 请求方式
Access-Control-Request-Headers: 自定义请求字段
// 当前服务器允许跨域的地址,可为*
Access-Control-Allow-Origin: 地址
//是否允许后续请求携带认证信息,该值只能是true,否则不返回
Access-Control-Allow-Credentials: true
// 预检结果缓存时间,单位毫秒
Access-Control-Max-Age: 1000
// 满足服务器要求的所有请求类型,不限于该次请求
Access-Control-Allow-Methods: GET,POST,PUT,POST
// 满足服务器要求的所有请求头字段,不限于该次请求
Access-Control-Allow-Headers: x-requested-with,content-type
跨域解决
这里前端使用原生 ajax(xhr)
首先我们使用ajax时需要设置允许跨域
// XMLHttpRequest对象,withCredentials为true则代表允许跨域
xhr.withCredentials = true;
接下来就是后端的操作了,例如我前端服务器地址为 localhost:8081
只需要在响应头加上
Access-Control-Allow-Origin: http://localhost:8081
Access-Control-Allow-Credentials: true
这里我用 JavaWeb的Servlet 写了个过滤器,可以直接复制修改使用
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 跨域响应过滤器.
* @author Shendi <a href='tencent://AddContact/?fromId=45&fromSubId=1&subcmd=all&uin=1711680493'>QQ</a>
* @version 1.0
*/
@WebFilter("/*")
public class CrosFilter extends HttpFilter {
private static final long serialVersionUID = 1L;
/** 允许跨域的地址 */
public static final String[] ORIGINS = {
"http://localhost:8081"
};
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String o = request.getHeader("Origin");
if (o != null) {
for (String origin : ORIGINS) {
if (o.equals(origin)) {
response.addHeader("Access-Control-Allow-Origin", o);
response.addHeader("Access-Control-Allow-Credentials", "true");
break;
}
}
}
chain.doFilter(request, response);
}
}