前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >正确配置 CORS:跨域问题解决记录

正确配置 CORS:跨域问题解决记录

作者头像
用户4945346
发布2024-06-17 18:51:45
2600
发布2024-06-17 18:51:45
举报
文章被收录于专栏:pythonista的日常pythonista的日常

最近和前端联调接口遇到了比较奇怪的跨域现象,连 GET 请求都被提示跨域错误。

跨域问题现象:

我们的服务都是基于 k8s 部署,在 ingress 这层都已经设置了允许跨域:

代码语言:javascript
复制
nginx.ingress.kubernetes.io/configuration-snippet: |
  # 允许来自所有来源的跨域请求。$http_origin 是一个变量,表示请求的来源地址。
  more_set_headers "Access-Control-Allow-Origin: $http_origin";
  # 允许跨域请求携带身份凭证(如 cookies)
  more_set_headers 'Access-Control-Allow-Credentials: true';
  # 设置了允许的HTTP请求方法。
  more_set_headers 'Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,OPTIONS';
  # 这行代码允许所有类型的HTTP头部。
  more_set_headers 'Access-Control-Allow-Headers: *';
  # 这段代码用于处理预检请求(OPTIONS请求)。如果请求方法是OPTIONS,直接返回204状态码(无内容),并结束请求。
  if ($request_method = 'OPTIONS') {
    return 204;
  }

通过排查 pod 和 ingress 的日志,发现 pod 服务并没有收到请求,则可能是 ingress 这段配置有些问题,通过上网搜索对上面的配置进行了优化。

解决:

在处理 OPTIONS 请求时又设置了一些头信息。改完之后的配置:

代码语言:javascript
复制
nginx.ingress.kubernetes.io/configuration-snippet: |
  if ($request_method = 'OPTIONS') {
    # 指定了预检请求( OPTIONS 请求)的结果可以缓存多久
    more_set_headers 'Access-Control-Max-Age: 3600';
    more_set_headers 'Access-Control-Allow-Origin: $http_origin';
    more_set_headers 'Access-Control-Allow-Credentials: true';
    more_set_headers 'Access-Control-Allow-Methods: *';
    more_set_headers 'Access-Control-Allow-Headers: *';
    return 204;
  }
  more_set_headers 'Access-Control-Allow-Origin: $http_origin';
  more_set_headers 'Access-Control-Allow-Credentials: true';
  more_set_headers 'Access-Control-Allow-Methods: *';
  more_set_headers 'Access-Control-Allow-Headers: *';

使用上面的配置就解决了跨域报错问题。通过本次问题的解决过程,又重新复习一下跨域的知识。

跨域概念

跨域(Cross-Origin Resource Sharing, CORS)是指在浏览器中,当一个网页从一个域名(origin)向另一个域名请求资源时,由于安全原因,浏览器会限制这些请求。这种限制被称为“同源策略”,它是为了防止恶意网站读取另一个网站的敏感信息。

跨域是指当一个网页试图从不同的域、协议或端口请求资源时,浏览器会阻止这些请求。例如:

代码语言:javascript
复制
从 http://example.com 向 http://api.example.com 请求资源

从 http://example.com 向 https://example.com 请求资源

从 http://example.com:80 向 http://example.com:8080 请求资源

为了解决跨域问题,可以使用 CORS 机制。通常在 nginx 或者后端服务配置CORS规则通过设置 HTTP 头来告诉浏览器允许哪些跨域请求。常用的 CORS 头包括:

代码语言:javascript
复制
Access-Control-Allow-Origin:指定允许访问资源的域名。
Access-Control-Allow-Methods:指定允许的 HTTP 方法(例如,GET、POST)。
Access-Control-Allow-Headers:指定允许的 HTTP 头信息。
Access-Control-Allow-Credentials:指示是否允许发送 Cookie。
Access-Control-Max-Age:指定预检请求的结果可以缓存多长时间。

简单请求和复杂请求

在跨域资源共享(CORS)中,根据请求的复杂程度,浏览器将跨域请求分为简单请求和复杂请求。

简单请求是指满足以下条件的跨域请求:

请求方法:

代码语言:javascript
复制
GET
HEAD
POST

请求头信息(除了自动设置的头信息外,不能包含其他自定义头信息):

代码语言:javascript
复制
Accept
Accept-Language
Content-Language
Content-Type(仅限于以下三种内容类型)
    text/plain
    multipart/form-data
    application/x-www-form-urlencoded

对于简单请求,浏览器会自动添加一个 Origin 头信息,表示请求的来源。当服务器收到请求后,如果允许跨域访问,则在响应头中添加相应的 CORS 头信息:

代码语言:javascript
复制
Access-Control-Allow-Origin
Access-Control-Allow-Credentials(如果需要允许发送凭证,如 Cookies)

复杂请求是不满足简单请求条件的跨域请求。对于复杂请求,浏览器会在实际请求之前发送一个预检请求(preflight request)。预检请求使用 OPTIONS 方法,目的是询问服务器是否允许实际请求。

预检请求包含以下请求头信息:

代码语言:javascript
复制
Origin:请求的来源。
Access-Control-Request-Method:实际请求将使用的 HTTP 方法。
Access-Control-Request-Headers:实际请求将使用的自定义头信息。

如果服务器允许请求,则返回带有适当头信息的响应,并且浏览器会继续发送实际请求。否则,浏览器将阻止实际请求。

简单来说:

简单请求:满足特定条件(方法和头信息)的跨域请求,直接发送,不需要预检请求。

复杂请求:不满足简单请求条件的跨域请求,浏览器会先发送预检请求,以确定服务器是否允许实际请求。

总结此次跨域错误排查的经历,我们不仅复习了跨域相关的知识,还系统地探讨了跨域问题的成因及其解决方法,并详细介绍了简单请求和复杂请求的区别和处理方式。希望这些内容对你有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 pythonista的日常 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档