【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

调用 Express API 时出现奇怪的 CORS 错误该怎么办?

  • 2020-12-18
  • 本文字数:3288 字

    阅读完需:约 11 分钟

调用 Express API时出现奇怪的CORS错误该怎么办?

想象一下这样一个场景:你用 Express 创建了一个 API,然后给前端加了一些 JavaScript 代码,这些 JS 代码会向这个 API 发送请求。事情本来很顺利,然后你在浏览器中加载了前端,突然在控制台中看到了一个奇怪的错误:


Access to fetch at 'https://your-api.com/user/1234' from origin 'https://your-website.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
复制代码


然后你可能会试着按照错误消息的提示,将请求的模式设置为 no-cors,但是对 API 的请求还是跑不通。就算你在网上搜索一番,也很难搞清楚为什么会发生这种事情,该怎么才能解决它。


好消息是,有一个 Express 库可用来修复这些 CORS 错误,但在我们着手解决这些错误之前,我们是不是该看看它们到底是什么意思?为了理解这些错误,我们先来看一下 CORS 究竟是什么。


什么是 CORS?为什么它会毁掉你美好的一天?


CORS 是跨域资源共享(Cross-Origin Resource Sharing)的简写,并且所有现代浏览器都支持它。这个概念有点拗口,所以我们把它拆开来细看,才能了解它到底做的是什么事情。


什么是“资源”?


资源是可在特定 URL 获取的内容,如 HTML 网页、图像或 JSON API 响应。实际上,它是构成万维网的“砖块”。


什么是“来源”?


一份资源的来源(origin)是协议+域+端口,例如网址https://your-api.com:8080/user/1234的源是https://your-api.com:8080。如果网址不包含端口,则源就只有协议+域。


跨域资源共享到底是做什么的?


当 Web 浏览器需要确保网站的前端 JavaScript(来源 A)仅在另一来源(来源 B)明确允许的情况下才可以访问 B 的资源时,就要用到跨域资源共享。如果来源 B 确实给出了许可,那么资源就会跨域共享!


CORS 可以帮助阻止恶意网站访问和使用敏感数据。当你在浏览器中看到那些烦人的 CORS 错误时,实际上是你的 Web 浏览器正在尽最大努力保护你免受被识别为潜在恶意请求的威胁。


CORS 如何工作?


Web 浏览器决定是否允许跨域共享资源时,会在前端 JavaScript 发出的请求上设置 Origin 标头。然后,浏览器检查在资源响应上设置的 CORS 标头。它在响应上检查的标头取决于浏览器发出的请求类型,但响应至少必须将 Access-Control-Allow-Origin 标头设置为一个受许可的值,才能让 Web 浏览器对发起请求的前端 JavaScript 给出响应。


CORS 请求示例


跨域请求的一个示例是,从网页上的前端 JavaScript(托管在一个域「来源 A」上)发起一个 GET 请求,到你托管在另一个域(来源 B)的 API 端点上。


浏览器通过https://your-website.com/user-profile网页上的 JavaScript 发出的请求将包含以下信息:


> GET /user/1234 HTTP/1.1> Host: your-api.com> Origin: https://your-website.com
复制代码


Origin 请求标头是由 Web 浏览器自动设置的——出于安全原因,通过 fetch 请求时无法设置其值。为了让上面的示例 CORS 请求正确运行,你的 API 发出的响应应该是这个样子:


< HTTP/1.1 200 OK< Access-Control-Allow-Origin: https://your-website.com< Vary: Origin< Content-Type: application/json; charset=utf-8< {"name":"Existing Person"}
复制代码


请注意,Access-Control-Allow-Origin 响应标头的值与 Origin 响应的值是呼应的:https://your-website.com。Web 浏览器会看到这个 CORS 响应标头,并确认它具有与网页上的前端 JavaScript 共享响应内容的权限。现在我们对 CORS 的概念和作用有了更好的了解,是时候设置一些 CORS 标头并修复你在网页上遇到的错误了。


如何设置 CORS 标头并摆脱那些烦人的错误


如你在上面的示例中所看到的,对于 Web 浏览器来说,在对 API 的请求中发送 Origin 标头是很重要的,但在响应中发送所有重要的 Access-Control-*标头的是你的 API。这些 CORS 标头会告诉 Web 浏览器是否允许将来自 API 的响应提供给前端 JavaScript。


为了帮助你解决你烦人的 CORS 错误,你需要用到 cors middleware package 这个库。在终端中转到包含 Express 应用程序的目录,然后安装它:


npm install cors
复制代码


注意:在这篇博客文章中,我会链接到 GitHub(而非 npm)上的 cors 软件包,因为在撰写本文时,npm 上的这个包的文档已经过时了。


安装完成后,你需要在应用程序中 require 它(require express 之后直接处理它即可):


const cors = require("cors");
复制代码


如果在不传递任何配置选项的情况下在 Express 应用程序中调用 cors 中间件,则默认情况下,它将在 API 响应中添加 CORS 响应标头 Access-Control-Allow-Origin: *。这意味着任何来源(即任何域上的网页)都可以向你的 API 发出请求。除非你要构建供公众使用的 API,否则你肯定不希望这么做。因此我们需要配置 cors 中间件,配置成只有你的网站才能向你的 API 发出 CORS 请求:


/** * These options will be used to configure the cors middleware to add * these headers to the response: *  * Access-Control-Allow-Origin: https://your-website.com * Vary: Origin */const corsOptions = {  origin: "https://your-website.com"};/** * This configures all of the following routes to use the cors middleware * with the options defined above. */app.use(cors(corsOptions));app.get("/user/:id", (request, response) => {  response.json({ name: "Existing Person" });});app.get("/country/:id", (request, response) => {  response.json({ name: "Oceania" });});app.get("/address/:id", (request, response) => {  response.json({ street: "Gresham Lane", city: "Lakeville" });});
复制代码


一般来说,你需要像上面的示例一样为 Express 应用程序中的所有路由启用 CORS,但是如果你只想为特定路由启用 CORS,则可以按以下方式配置 cors 中间件:


/** * These options will be used to configure the cors middleware to add * these headers to the response: *  * Access-Control-Allow-Origin: https://your-website.com * Vary: Origin */const corsOptions = {  origin: "https://your-website.com"};// This route is using the cors middleware with the options defined above.app.get("/user/:id", cors(corsOptions), (request, response) => {  response.json({ name: "Existing Person" });});// This route is using the cors middleware with the options defined above.app.get("/country/:id", cors(corsOptions), (request, response) => {  response.json({ name: "Oceania" });});/** * We never want this API route to be requested from a browser, * so we don't configure the route to use the cors middleware. */app.get("/address/:id", (request, response) => {  response.json({ street: "Gresham Lane", city: "Lakeville" });});
复制代码


启用“复杂”CORS 请求


上面的示例是为简单的 GET 请求配置 CORS 的。对于其他许多类型的 CORS 请求,Web 浏览器将在发出实际 CORS 请求之前先发出 CORS“预检”(pre-flight)请求。这个预请求使用了 OPTIONS HTTP 方法,它可以帮助浏览器确定是否允许发出 CORS 请求。


cors 中间件提供了启用 CORS 预检的说明,并允许你配置在对预检请求的响应中发送的标头。


不用再担心 COR 了 S


希望本文能够帮助你全面了解 CORS,但有时我们确实很难弄清楚如何配置才能让 CORS 请求正常工作。下面列举一些有用的资源:



祝大家跨域资源共享愉快!


原文链接:How To Fix Those Confusing Cors Errors When Calling Your Express API

2020-12-18 11:552089

评论

发布
暂无评论
发现更多内容

2022年1月国产数据库排行榜:TiDB霸榜两年势头不减,openGauss与OceanBase分数大涨

墨天轮

数据库 opengauss TiDB 国产数据库

凡泰极客荣获2021 InfoQ“最佳技术产品营销奖”

FinClip

InfoQ

投票开始 | 和你一起见证龙蜥社区年度优秀开发者的诞生

OpenAnolis小助手

开源 开发者 活动 社群 比赛

征集用户| 填写 2022 Apache Pulsar 用户调查问卷,抽取丰厚礼品

Apache Pulsar

开源 云原生 中间件 Apache Pulsar 社区

面试突击19:为什么ConcurrentHashMap不允许插入null值?

王磊

OpenCloudOS开源操作系统社区迎来首个正式版本

科技热闻

深度评测丨GaussDB(for Redis)大Key操作的影响

华为云开发者联盟

redis 运维 GaussDB(for Redis) 大Key KV查询

CWE视图层级关系解析:节点关系查询

华为云开发者联盟

软件开发 cwe 软件缺陷 CWE视图层级关系 节点关系

华为云FusionInsight连续三次获得第一 加速释放数据要素价值

数据湖洞见

大数据 FusionInsight 华为云

Flink 流批一体平台 StreamX 1.2.1 正式发布

ApacheStreamPark

spark FlinkSQL 流批一体 Flink 平台 一站式平台

Hive SQL语句的正确执行顺序

五分钟学大数据

1月月更

为什么需要闭包?闭包是什么概念?

蜜糖的代码注释

Java 后端 开发

鸿蒙轻内核源码分析:虚拟文件系统VFS

华为云开发者联盟

鸿蒙 文件系统 鸿蒙轻内核源码 虚拟文件系统VFS 虚拟文件系统

网易Go语言通用开发框架-Ngo开源啦

月读

golang Go 语言 开源治理 开源中国

专访深职院XR专家 | 实时云渲染赋能虚拟仿真实训,打造5G+XR智慧教育平台

3DCAT实时渲染

教育 XR VR/AR 云渲染 元宇宙

做了这么多年架构师,我终于理解了什么是架构设计

博文视点Broadview

请求管理 | 洞态 IAST 在好大夫 SDL 中的最佳实践

火线安全

信息安全 SDL DevSecOps

Hive底层数据存储格式详解

五分钟学大数据

hive 1月月更

品高股份加入,龙蜥社区迎来又一家云计算厂商

OpenAnolis小助手

Linux 开源

重新学架构之微信业务与学生管理系统

陈华英

「架构实战营」

多方计算时,每次结果竟然都存在着巨大隐患,此文告诉你可以这样解决!

华为云开发者联盟

安全 多方计算 数据保护 华为云tics服务 差分隐私算法

V7.1:新字段“嵌入”,实现自定义元素交互

明道云

拍乐云发布互动白板2.0,首创超高清文档演示和滚动浏览

拍乐云Pano

WebRTC RTC opengl

使用 Lambda 表达式实现超强的排序功能

CRMEB

告警关联中的频繁项集挖掘问题

云智慧AIOps社区

算法 智能运维 智能告警 人工智能「 云智慧

企业微信业务架构分析

Geek_1b4338

#架构实战营

模块一作业

Geek_ec866b

架构实战营

面试官太难伺候?一个try-catch问出这么多花样

阿Q说代码

效率 字节码指令 1月月更 try-catch finally-return

Android C++系列:JNI中的Handler--ALooper

轻口味

c++ android jni 1月月更

把复杂交给我们,把简单还给你丨TiVP 让 SQL 执行计划可视化

PingCAP

小程序开发中使用 JS

Speedoooo

调用 Express API时出现奇怪的CORS错误该怎么办?_语言 & 开发_Simon Plenderleith_InfoQ精选文章