CORS错误发生在将multipart/form-data添加到请求头时。

huangapple go评论85阅读模式
英文:

CORS error when multipart/form-data was added to request header

问题

我在前端使用ReactJs,后端使用Laravel,以及Nginx作为Web服务器。当我将multipart/form-data添加到axios的POST请求时,出现了CORS错误。项目是Docker化的,后端端口是8090,前端端口是8080。

这是我的axios请求代码:

const result = await axios(`${backendUrl}/shops`, {
  headers: {
    'Content-Type': `multipart/form-data; `,
    "Accept": "*/*",
    "Access-Control-Allow-Origin": "*"
  },
  method: "post",
  data: {
    values
  },
  withCredentials: true,
});

我尝试在Laravel核心配置文件中禁用CORS策略。这是我的Laravel CORS配置文件:

'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

我还在Nginx配置文件中添加了client_max_body_size,但错误没有得到解决。

英文:

I'm using ReactJs in frontend and Laravel in backend and nginx as web server.
When I add multipart/form-data to axios post request I get the cors error:
It's considerablw that the project is dockerized.
The backend port is 8090 and frontend port is 8080.

const result = await axios(`${backendUrl}/shops`, {
  headers: {
      'Content-Type': `multipart/form-data; `,
      "Accept": "*/*",
      "Access-Control-Allow-Origin": "*"
  },
      method: "post",
      data: {
          values
      },
      withCredentials: true,
    });

I tried to disable cors policy in larevl core config file.
This is my Laravel cors config file:

'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,

I added client_max_body_size to nginx config file but the error didn't get resolved.

答案1

得分: 0

首先,您应该从您的axios请求中删除Access-Control-Allow-Origin头,因为它是服务器端响应头。

其次,由于您正在使用带凭证的请求,您的后端不能响应Access-Control-Allow-Origin: *

对于不带凭证的请求,可以指定字面值"*"作为通配符;该值告诉浏览器允许来自任何源的请求代码访问资源。尝试在带凭证的情况下使用通配符会导致错误。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials

以下是您可以验证您的后端是否正确配置以处理带凭证的CORS请求的方式(您需要将http://localhost:3000替换为您的前端源,将http://localhost:3100/api/test替换为您的后端API端点)。

  1. 验证OPTIONS响应中是否存在访问控制头:
curl -v -X OPTIONS -H "Origin: http://localhost:3000" http://localhost:3100/api/test
*   Trying 127.0.0.1:3100...
* Connected to localhost (127.0.0.1) port 3100 (#0)
> OPTIONS /api/test HTTP/1.1
> Host: localhost:3100
> User-Agent: curl/7.88.1
> Accept: */*
> Origin: http://localhost:3000
> 
< HTTP/1.1 200 OK
< vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Origin
< access-control-allow-credentials: true
< access-control-allow-methods: POST
< access-control-allow-origin: http://localhost:3000
< access-control-max-age: 300
< date: Fri, 07 Jul 2023 13:13:13 GMT
< connection: close
< transfer-encoding: chunked
< 
* Closing connection 0
  • access-control-allow-credentials: true - 此头必须出现在响应中
  • access-control-allow-methods: POST - 此头必须存在,必须包括POST
  • access-control-allow-origin: http://localhost:3000 - 此头必须存在,必须包括您的前端源
  • access-control-max-age: 300 - 此头是可选的;在开发环境中,您可以将最大年龄设置得相对较短
  • vary: Origin - 此头是推荐的
  1. 验证POST响应中是否存在访问控制头:
curl -v -F param=value -H "Origin: http://localhost:3000" http://localhost:3100/api/test
*   Trying 127.0.0.1:3100...
* Connected to localhost (127.0.0.1) port 3100 (#0)
> POST /api/test HTTP/1.1
> Host: localhost:3100
> User-Agent: curl/7.88.1
> Accept: */*
> Origin: http://localhost:3000
> Content-Length: 145
> Content-Type: multipart/form-data; boundary=------------------------6a23bcb7ccaed2ec
> 
* We are completely uploaded and fine
< HTTP/1.1 200 OK
< vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Origin, Accept-Encoding
< access-control-allow-credentials: true
< access-control-allow-methods: POST
< access-control-allow-origin: http://localhost:3000
< access-control-max-age: 300
< content-type: application/json
< date: Fri, 07 Jul 2023 13:19:47 GMT
< connection: close
< transfer-encoding: chunked
< 
* Closing connection 0

至少,您的POST响应必须包含Access-Control-Allow-OriginAccess-Control-Allow-Credentials头,但在OPTIONS响应中包括与之相同的访问控制头是没有问题的。

请告诉我这是否解决了您的问题。如果问题仍然存在,请还请提供具体的CORS错误。

英文:

First of all, you should remove the Access-Control-Allow-Origin header from your axios request since it's a server-side response header.

Second, since you are using credentialed request your backend can't respond with Access-Control-Allow-Origin: *

> For requests without credentials, the literal value "*" can be specified as a wildcard; the value tells browsers to allow requesting code from any origin to access the resource. Attempting to use the wildcard with credentials results in an error.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin#directives

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials

Here is how you can verify your backend is properly configured to handle credentialed CORS requests (you'll need to replace http://localhost:3000 with your frontend origin, and http://localhost:3100/api/test with your backend API endpoint).

  1. Verify access control headers are present in the OPTIONS response:
curl -v -X OPTIONS -H &quot;Origin: http://localhost:3000&quot; http://localhost:3100/api/test
*   Trying 127.0.0.1:3100...
* Connected to localhost (127.0.0.1) port 3100 (#0)
&gt; OPTIONS /api/test HTTP/1.1
&gt; Host: localhost:3100
&gt; User-Agent: curl/7.88.1
&gt; Accept: */*
&gt; Origin: http://localhost:3000
&gt; 
&lt; HTTP/1.1 200 OK
&lt; vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Origin
&lt; access-control-allow-credentials: true
&lt; access-control-allow-methods: POST
&lt; access-control-allow-origin: http://localhost:3000
&lt; access-control-max-age: 300
&lt; date: Fri, 07 Jul 2023 13:13:13 GMT
&lt; connection: close
&lt; transfer-encoding: chunked
&lt; 
* Closing connection 0
  • access-control-allow-credentials: true - this header must be present in the response
  • access-control-allow-methods: POST - this header must be present and must include POST
  • access-control-allow-origin: http://localhost:3000 - this header must be present and must include your frontend origin
  • access-control-max-age: 300 - this header is optional; you can set the max-age to be reasonably short in dev environment
  • vary: Origin - this header is recommended
  1. Verify access control headers are present in the POST response:
curl -v -F param=value -H &quot;Origin: http://localhost:3000&quot; http://localhost:3100/api/test
*   Trying 127.0.0.1:3100...
* Connected to localhost (127.0.0.1) port 3100 (#0)
&gt; POST /api/test HTTP/1.1
&gt; Host: localhost:3100
&gt; User-Agent: curl/7.88.1
&gt; Accept: */*
&gt; Origin: http://localhost:3000
&gt; Content-Length: 145
&gt; Content-Type: multipart/form-data; boundary=------------------------6a23bcb7ccaed2ec
&gt; 
* We are completely uploaded and fine
&lt; HTTP/1.1 200 OK
&lt; vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch, Origin, Accept-Encoding
&lt; access-control-allow-credentials: true
&lt; access-control-allow-methods: POST
&lt; access-control-allow-origin: http://localhost:3000
&lt; access-control-max-age: 300
&lt; content-type: application/json
&lt; date: Fri, 07 Jul 2023 13:19:47 GMT
&lt; connection: close
&lt; transfer-encoding: chunked
&lt; 
* Closing connection 0

As a bare minimum, your POST response must include Access-Control-Allow-Origin and Access-Control-Allow-Credentials headers, but there is no harm in including the same access control headers as in the OPTIONS response.

Please let me know if this resolves your issue. Please also post the specific CORS error if the issue doesn't go away.

答案2

得分: 0

问题已通过对请求进行微小更改来解决。
我将方法类型从请求体移至请求的第一行,并将值附加到 formData,然后将其作为请求的第二个参数发送,并将边界添加到请求头:

const result = await axios.post(`${backendUrl}/shops`, formData, {
                    headers: {
                        'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
                    },
                    withCredentials: true,
                });
英文:

The issue has been solved by tiny changes in request.
I moved the method type from request body to request first line and append values to formData and sent it as the second argument of request and added boundary to request header:

const result = await axios.post(`${backendUrl}/shops`, formData, {
                    headers: {
                        &#39;Content-Type&#39;: `multipart/form-data; boundary=${formData._boundary}`,
                    },
                    withCredentials: true,
                });

huangapple
  • 本文由 发表于 2023年7月7日 02:47:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76631739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定