前言
相信很多人都在面试中被问过什么是跨域,怎么解决跨域。本文不列举跨域的几种方式,但是会用简单的文字描述CORS,力求CORS能被轻松的理解。
同源
协议、域名、端口号都相同时,才算是同源。反之,则是非同源。
跨域
由于浏览器同源策略,浏览器直接从脚本内发起的非同源HTTP请求不会得到正常的成功的响应。
CORS
CORS全称跨域资源共享,它解决了当跨域访问资源时,浏览器和服务器的如何沟通的问题。换句话说,就是使用CORS可以解决跨域的问题。
简单请求
若请求满足所有下述条件,则该请求可视为简单请求。
-
使用下列方法之一
- GET
- HEAD
- POST
-
除了下列三种
- 被用户代理自动设置的首部字段(例如Connection,User-Agent)
- 在Fetch规范中定义为禁用首部名称的其他首部
- 允许人为设置的字段为Fetch规范定义的对CORS安全的首部字段集合(Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width)
-
Content-Type的值仅限于下列三者之一
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
-
请求中的任意XMLHttpRequestUpload对象均没有注册任何事件监听器(XMLHttpRequestUpload对象可以使用XMLHttpRequest.upload属性访问)
-
请求中没有使用ReadableStream对象
非简单请求
与简单请求不同,非简单请求要求必须首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。如果允许,浏览器就会再发起一个实际请求。如果不允许,服务器响应头中是没有CORS相关的头信息字段。
CORS配置
浏览器设置
import axios from 'axios'
const token = localStorage.getItem('token')
const request = ({ url, method, data, success, error }) => {
axios({
url: url,
method: method,
data: data,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'B2B-Authorization': token == null ? '' : token
}
})
.then(res => {
//成功
if (typeof success === 'function') {
success(res)
}
})
.catch((err) => {
//失败
if (typeof error === 'function') {
error(err)
}
})
}
export default request
这段代码调用时,只要不同源,就会产生跨域并且发送非简单请求。
NGINX服务器配置
server
{
listen 3002;
server_name localhost;
location /ok {
proxy_pass http://localhost:3000;
# 指定允许跨域的方法,*代表所有
add_header Access-Control-Allow-Methods *;
# 预检命令的缓存,如果不缓存每次会发送两次请求
add_header Access-Control-Max-Age 3600;
# 带cookie请求需要加上这个字段,并设置为true
add_header Access-Control-Allow-Credentials true;
# 表示允许这个域跨域调用(客户端发送请求的域名和端口)
# $http_origin动态获取请求客户端请求的域 不用*的原因是带cookie的请求不支持*号
add_header Access-Control-Allow-Origin $http_origin;
# 表示请求头的字段 动态获取
add_header Access-Control-Allow-Headers
$http_access_control_request_headers;
# OPTIONS预检命令,预检命令通过时才发送请求
# 检查请求的类型是不是预检命令
if ($request_method = OPTIONS){
return 200;
}
}
}
相关的HTTP首部字段
请求首部字段
- Origin
表明预检请求或实际请求的源站。
- Access-Control-Request-Method
用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。
- Access-Control-Request-Headers
用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。
响应首部字段
- Access-Control-Allow-Origin
表示允许来自所有域的请求/具体域的请求。
- Access-Control-Expose-Headers
让服务器把允许浏览器访问的头放入白名单。这样浏览器就能够通过getResponseHeader访问白名单中的响应头了。
- Access-Control-Max-Age
指定了preflight请求的结果能够被缓存多久。
- Access-Control-Allow-Credentials
指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。
- Access-Control-Allow-Methods
用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。
- Access-Control-Allow-Headers
用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
谢谢阅读!