问题描述:
在进行文件上传时,由于后端服务器有多个,所以在上传地址之前,会先调用后端的一个接口,获取实际的上传地址。但是每次获取的上传地址都不一样,使用ngnix解决跨域问题不切实际,所以后端开启cors,跨域资源共享。但是后面还是报错。
报错:
Access to XMLHttpRequest at 'http://192.168.1.XXX:9191/mpn/file/4715ff4efb35423c87972aa2c959bdf2' from origin 'http://192.168.3.XXX:8089' has been blocked by CORS policy: Request header field x-cs-content-length is not allowed by Access-Control-Allow-Headers in preflight response.
抓包:
对于这个上传文件的请求进行抓包,查看请求头发现
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, Content-Type, AccessToken, X-CSRF-Token, Authorization, Token
Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type
Content-Type: application/json; charset=utf-8
Date: Thu, 07 Jul 2022 05:54:20 GMT
Content-Length: 158
Connection: clos
红色字体标明的为后端允许跨域的请求头
而我自定义的请求头为:
headers: {
'Content-Type': 'application/octet-stream', 'x-cs-content-method': me,
'x-cs-content-length': allLength, 'x-cs-range': bytes, 'ETag': ETag,
}
产生问题的原因:
前端定义了后端不被允许跨域的请求头
解决办法:
后端自定义增加允许跨域的请求头,如python:
# 后端是python的话
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = default_headers + (
'允许跨域的请求头'
)
扩展:
参考博客:你知道为何跨域中会发送 options 请求? - 掘金
在每次上传文件的时候,浏览器都会发送两次请求
第一次请求显示类型为 preflight,启动器显示为预检
并且查看标头,这个请求的 方法为OPTIONS
1、产生原因:
在CORS机制中,客户端(浏览器)将请求分为两种,简单请求和复杂请求
对于简单请求,需要满足以下的要求:
- 请求方法为:GET 、POST 、 HEAD
- 请求头:Accept、Accept-Language、Content-Language、Content-Type
其中 Content-Type 限定为 :
text/plain、multipart/form-data、application/x-www-form-urlencoded
而我现在的请求方法为 Put ,并且自定义了请求头,所以当然属于复杂方法,需要被预检
2、作用:
为什么要进行预检呢?
- 获取服务器支持的HTTP请求方法;
- 用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。
3、过程:
参考文档:http CORS options请求(预检请求)详解 - 知乎
a.对于简单请求:
浏览器直接发送CORS请求这一次请求,并会额外携带一个请求头参数:Origin
Origin : http://192.168.3.229:8089
这个参数里面显示了本次请求来自哪个源(协议 、域名、端口)。服务器根据这个值,决定是否同意这次请求。
如果Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
b.对于复杂请求:
浏览器会先进行一次预检请求,请求方法为OPTIONS,携带了两个重要的请求头信息:
Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,我使用的是Put方法
Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
浏览器通过预检请求返回的信息判断,真正要发送的请求携带的信息(请求头、方法)是否被服务器接纳,以及当前网页所在的域名是否在服务器的许可名单之中,只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
预检请求的返回信息:
Access-Control-Allow-Origin:*
有这个字段,表示允许跨域
如果不包含这个字段的话,就证明服务器不接受这个请求,请求失败
PS:如果还是失败的话,要检查后端允许的方法种是否包含了请求使用的方法