欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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;

可以直接使用这个里面的ajax封装

 

接下来就是后端的操作了,例如我前端服务器地址为 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);
	}
	
}