问题描述:

在进行文件上传时,由于后端服务器有多个,所以在上传地址之前,会先调用后端的一个接口,获取实际的上传地址。但是每次获取的上传地址都不一样,使用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机制中,客户端(浏览器)将请求分为两种,简单请求和复杂请求

        对于简单请求,需要满足以下的要求:

  • 请求方法为:GETPOSTHEAD
  • 请求头:AcceptAccept-LanguageContent-LanguageContent-Type

其中 Content-Type 限定为 :

text/plain、multipart/form-data、application/x-www-form-urlencoded

         而我现在的请求方法为 Put ,并且自定义了请求头,所以当然属于复杂方法,需要被预检

2、作用:

        为什么要进行预检呢?

  1. 获取服务器支持的HTTP请求方法;
  2. 用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。

 3、过程:

参考文档:http CORS options请求(预检请求)详解 - 知乎

        a.对于简单请求:

        浏览器直接发送CORS请求这一次请求,并会额外携带一个请求头参数:Origin

        ​​​​​​Origin : http://192.168.3.229:8089

        这个参数里面显示了本次请求来自哪个源(协议 、域名、端口)。服务器根据这个值,决定是否同意这次请求。 

        如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

b.对于复杂请求:

        浏览器会先进行一次预检请求,请求方法为OPTIONS,携带了两个重要的请求头信息:

 Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,我使用的是Put方法

Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段

         浏览器通过预检请求返回的信息判断,真正要发送的请求携带的信息(请求头、方法)是否被服务器接纳,以及当前网页所在的域名是否在服务器的许可名单之中,只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

        预检请求的返回信息:

        Access-Control-Allow-Origin:*

        有这个字段,表示允许跨域

        如果不包含这个字段的话,就证明服务器不接受这个请求,请求失败

PS:如果还是失败的话,要检查后端允许的方法种是否包含了请求使用的方法
 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐