什么是同源策略?
比如:1. www.baidu.com:80 -> 2. baidu.com:80
首先 第1个地址 和 第2个地址最大的区别就是 http 协议不同 和 主机名 不同. 同源策略最核心的要点就是 http协议必须完全一致 主机名 必须完全一致 端口号必须完全一致 同源策略是浏览器防止网站数据被篡改的一种机制。
如下图所示:
如何进行跨域?
CORS
CORS(Cross-Origin Resource Sharing)是一种机制,它允许浏览器向跨源服务器发出资源请求。浏览器通常会在跨源的 HTTP 请求中添加一个 Origin 头,表示请求来自哪个源。服务器如果希望它可以被跨域访问,就可以在响应中添加一个 Access-Control-Allow-Origin 头,表示允许哪个源访问。
CORS的本质就是允许服务器通过设置 HTTP 头来告诉浏览器,哪些域名、协议、端口可以访问资源。如果浏览器发现自己无法访问资源,就会在后台向服务器发送一个预检请求(preflight request),询问服务器是否允许跨域访问。服务器如果允许,就会在响应中添加 Access-Control-Allow-Origin 头,告诉浏览器可以发起正式的跨域请求。
当然这里分为简单请求和复杂请求的.
比如: A 通过响应头告诉浏览器,我愿意共享给 B 这就是一个简单请求
复杂请求就是 浏览器为了防止 POST/PUT/PATCH 请求对数据造成影响
可能复杂请求解释的不是很通俗. 复杂请求就是 比如 你在前端使用
xhr.open('POST', 'https://baidu.com:8888/data')
xhr.setRequestHeader('aliyu', '23')
你的网站 aliyu.com 这个主机要访问百度服务器上的/data这个接口的话, 那么在百度服务器后端代码里面就需要设置以下三个
Access-Control-Allow-Origin 设置这个头 对应的 主机 aliyu.com:80。 设置这个的意思就是说 以后 aliyu.com:80 这个地址发送过来的请求都可以访问。
Access-Control-Allow-Methods 这个这个头的意思就是一个 HTTP 头,用于告诉浏览器哪些 HTTP 方法可以跨域访问。
写法:
'Access-Control-Allow-Methods', 'POST, GET, OPTIONS'
当浏览器发现自己无法访问某个资源时,会在后台发送一个预检请求(preflight request)。预检请求的方法是 OPTIONS,它的目的是询问服务器是否允许跨域访问。服务器如果允许,就会在响应中添加 Access-Control-Allow-Methods 头,表示浏览器可以发起哪些方法的跨域请求。
例如,如果服务器允许浏览器发起 GET 和 POST 请求,就可以返回如下响应:
HTTP/1.1 200 OK
Access-Control-Allow-Methods: GET, POST
浏览器收到这个响应后,就可以发起 GET 和 POST 请求。如果浏览器想要发起其他方法的请求,比如 DELETE 或 PUT,就会再次发起预检请求,询问服务器是否允许跨域访问。
注意,Access-Control-Allow-Methods 头只能在响应预检请求时使用。正式的跨域请求(比如 GET 或 POST)不会携带这个头。
JSONP
JSONP(JSON with Padding)是一种在浏览器端跨域访问资源的技术。通过动态插入一个 <script> 标签的方式,实现跨域访问。
在使用 JSONP 的情况下,浏览器会向服务器发送一个带有回调函数名的请求,例如:
GET https://baidu.com/resource?callback=foo
服务器收到请求后,会返回一个带有回调函数调用的 JSON 格式的响应,例如:
foo({ "aliyu": "23" });
浏览器会解析这个响应,并调用名为 foo 的回调函数,传入解析后的 JSON 对象。
由于 JSONP 使用的是动态插入的 <script> 标签,所以它不受浏览器的同源策略限制。但是,由于它是通过动态插入的方式实现跨域访问,所以它只能用于发起 GET 请求,不能用于发起其他类型的请求(比如 POST、DELETE 等)。
JSONP 已经被 CORS 取代.
反向代理(Nginx)之跨域
- 在反向代理服务器上设置跨域访问策略。反向代理服务器需要添加
Access-Control-Allow-Origin头,表示允许浏览器访问指定的域名。或者向代理服务器添加proxy_pass例如:
//允许 http://a.com:8888 访问
假设你的网站是b.com 那么你就必须在代理服务器去后端发送请求访问 a.com 这样就是服务器去请求 请求到数据后返回给b.com你自己. 然后前端就可以直接访问 b.com/data 拿到数据了
location /data {
proxy_pass http://a.com:8888;
}
//允许任意 域名 或者 ip 访问
location / {
proxy_set_header Access-Control-Allow-Origin *;
}
- 在前端中,使用反向代理服务器的地址发起跨域请求。例如:
fetch('http://b.com/data')
.then(response => response.json())
.then(data => console.log(data));
这样,浏览器会向反向代理服务器发起请求,反向代理服务器再将请求转发到目标服务器。由于反向代理服务器已经设置了跨域访问策略,所以浏览器就可以正常地访问目标服务器了。
注意,反向代理服务器只能用于解决前端跨域访问的问题。如果服务器端的 API 需要跨域访问,就需要在服务器端设置跨域访问策略,比如使用 CORS。