第五章 跨域资源共享(CORS):现代Web开发中的关键机制

简介: 第五章 跨域资源共享(CORS):现代Web开发中的关键机制

引言

在现代Web开发中,不同源之间数据交换的需求日益增长。然而,出于安全原因,浏览器对从一个域向另一个域发起请求有着严格的限制,这就是同源策略(Same-Origin Policy)。


然而,同源策略限制了后端访问接口必须与网站一致!这就非常不灵活,尤其现在web应用多为多端应用,又同时需要多个地址的服务的情况下。(这里是重点)

为了解决这一问题,并实现安全、灵活的跨域通信,跨域资源共享(Cross-Origin Resource Sharing, 简称CORS)应运而生。本文将深入探讨CORS的工作原理、配置方法及其在实际应用中的重要性。

一、同源策略与跨域限制

1. 概念

同源策略(Same-Origin Policy)是浏览器为保护用户信息安全而实施的一种安全机制。在Web开发领域,同源策略规定了来自同一来源的文档或脚本可以相互读取和交互数据,而不同源则不能直接进行这样的操作。这里的“源”由协议、域名和端口三部分组成,如果这三者完全相同,则认为两个资源是同源的。

2. 举例说明

  1. 同源示例
  • 这两个URL具有相同的协议(HTTPS)、相同的域名(www.example.com)和相同的端口(默认HTTP/HTTPS端口,即443),因此它们被认为是同源的,这个请求将被允许执行。
  1. 非同源示例
  • 当前网页地址为 https://www.example.com/index.html。
  • 页面尝试发送一个AJAX请求到 http://api.other-example.com/data
  • 这两个URL的协议不同(一个是HTTPS,另一个是HTTP),或者域名不同(www.example.com与api.other-example.com),因此它们被视为不同源。
  • 根据同源策略,浏览器将会阻止此跨域请求,除非服务器配置了支持跨域资源共享(CORS)并明确允许从www.example.com发起请求。

同源策略旨在防止恶意网站通过JavaScript读取其他站点的敏感信息,例如cookies或其他存储在本地的数据。对于需要进行跨域通信的应用场景,可以通过CORS、JSONP等技术实现安全可控的数据交换。

二、跨域资源共享(CORS)

1. 概念

首先要明确的是CORS是一种W3C标准(非常重要,是浏览器和服务器共同去完成的一套http请求机制),允许服务器明确声明哪些外部域可以访问其资源。通过CORS,服务器能够设置允许哪些HTTP请求方法、头信息和自定义响应头被其他域使用。


跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种允许网页从不同源(domain、协议或端口不一致)获取资源的机制。在Web开发中,由于浏览器的安全策略——同源策略(Same-Origin Policy),一个源下的文档或脚本默认情况下不能访问另一个源的资源。然而,在实际应用中,往往需要跨域请求以实现数据共享和服务调用。

2. CORS工作原理与举例说明

1. CORS请求类型

  • 简单请求:对于GET、POST等简单HTTP方法以及某些标准头部字段的请求,可以被视为简单请求。浏览器会自动在请求头中添加Origin字段,标识请求发起者的源。

示例:

GET /data HTTP/1.1
Host: api.example.com
Origin: https://www.example.net

服务器收到请求后,会在响应头中返回Access-Control-Allow-Origin来指定哪些源可以访问该资源。

2. 预检请求(Preflight Request)

对于非简单请求,如使用自定义头部字段或PUT、DELETE等其他HTTP方法的请求,浏览器会先发送一个OPTIONS预检请求询问服务器是否接受该跨域请求。

示例:

OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://www.example.net
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

-- Response --
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.net
Access-Control-Allow-Methods: PUT, POST, DELETE
Access-Control-Allow-Headers: X-Custom-Header

3. 服务器配置

服务器根据接收到的请求和自身的CORS策略,通过设置特定的响应头信息来决定是否允许这次跨域请求。

例如,服务器可以通过设置如下响应头允许来自https://www.example.net的请求:

Access-Control-Allow-Origin: https://www.example.net


4. CORS安全控制

CORS还提供了其他一些响应头用于更精细的权限控制,如:

  • Access-Control-Allow-Credentials 控制是否允许携带凭据(如 Cookies 或 HTTP 认证信息)进行跨域请求。
  • Access-Control-Max-Age 设置预检请求结果的有效期,减少重复预检次数。

三、CORS请求类型与流程

1. 简单请求

  • 对于GET、POST等简单HTTP方法以及一些特定的头部字段,浏览器可以直接发起跨域请求,无需预检。

浏览器会在请求头中自动添加Origin字段表明来源域,服务器根据此信息决定是否放行请求。

在浏览器发起跨域请求时,对于非简单请求(如包含了自定义头部、PUT、DELETE等方法的请求)和所有预检请求(OPTIONS),

  • 浏览器会自动在请求头中添加一个Origin字段。这个字段包含的是当前发出请求的页面所在的源信息,即协议+域名+端口。

如果一个网页加载自 https://example.com,当它尝试向 https://api.example.net 发送一个跨域请求时,浏览器会在请求头中插入如下内容:

Origin: https://example.com

服务器收到请求后,可以通过检查Origin头来判断请求是否来自允许访问的源。如果服务器配置了CORS策略,并且Access-Control-Allow-Origin响应头中包含了与请求头中的Origin相匹配的源,那么该请求将被放行;否则,请求会被服务器拒绝。

举个例子,服务器可以这样设置其CORS策略以允许来自https://example.com的请求:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com

2. 预检请求(Preflight Request)

  • 当请求方法不是简单的GET/POST或者包含自定义头部时,浏览器会先发送一个OPTIONS方法的预检请求来询问服务器。
  • 服务器收到预检请求后,若返回的响应头中包含了Access-Control-Allow-OriginAccess-Control-Allow-Methods等相关字段并允许当前源,则后续的实际请求会被正常处理。

预检请求(Preflight Request)是CORS机制中的一种特殊请求,用于非简单请求(例如使用了自定义头部字段、PUT、DELETE等方法的请求)在实际发送前向服务器询问是否允许该跨域请求。以下是一个关于预检请求的例子,包括客户端发起请求和服务器端响应:

3. 客户端JavaScript示例

// 使用fetch API 发起一个带有自定义头部的PUT请求
fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'custom-value'
  },
  body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));

在此例中,由于我们设置了自定义头部X-Custom-Header并使用了PUT方法,浏览器会先发送一个OPTIONS预检请求。

4. 服务器端响应示例(以Node.js + Express为例)

const express = require('express');
const app = express();

app.options('/data', (req, res) => { // 处理预检请求
  res.set({
    'Access-Control-Allow-Origin': 'https://www.example.net', // 允许特定源
    'Access-Control-Allow-Methods': 'PUT, POST, DELETE, OPTIONS', // 允许的方法列表
    'Access-Control-Allow-Headers': 'Content-Type, X-Custom-Header', // 允许的头部
    'Access-Control-Max-Age': 86400 // 预检结果缓存时间(单位秒)
  });

  if (req.headers.origin) {
    res.setHeader('Access-Control-Allow-Credentials', true); // 允许携带凭据(如 Cookies)
  }

  res.status(204).send(); // 预检请求不需要返回数据体,仅需设置正确的响应头
});

app.put('/data', (req, res) => {
  // 实际处理PUT请求逻辑
});

// ...其他路由...

app.listen(3000, () => console.log('Server started on port 3000'));

当客户端发起上述跨域PUT请求时,浏览器首先发送一个OPTIONS预检请求到服务器。如果服务器的预检响应表明允许该请求,则浏览器才会继续发送实际的PUT请求。

四、CORS响应头详解

  • Access-Control-Allow-Origin: 必需字段,指定允许接收请求的源。
  • Access-Control-Allow-Methods: 指定允许的方法列表,如GET, POST, PUT, DELETE等。
  • Access-Control-Allow-Headers: 允许客户端发送的非标准请求头。
  • Access-Control-Allow-Credentials: 表示是否允许携带cookie和认证信息进行跨域请求。
  • Access-Control-Max-Age: 设置预检请求结果的有效期,减少重复预检的次数。

五、CORS配置实例

在服务器端(如Node.js的Express框架),可以通过中间件实现CORS:

const express = require('express');
const app = express();

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有源
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); // 允许的方法
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // 允许的头部
  if (req.method === 'OPTIONS') {
    res.send(204); // 预检请求则直接返回204状态码
  } else {
    next(); // 其他请求继续执行路由处理函数
  }
});

// ... 添加你的路由逻辑 ...

六、CORS实践与安全性考量

尽管CORS极大地增强了Web应用程序的功能性和灵活性,但它也引入了一些潜在的安全风险,比如可能泄露敏感信息。因此,在实施CORS策略时务必谨慎,避免过于宽松的设置,如只允许特定可信的源访问资源,同时对允许的方法和头部进行严格控制。


总结来说,跨域资源共享作为现代Web开发的重要组成部分,对于构建高效、安全且具有丰富交互体验的应用至关重要。理解并正确配置CORS不仅能解决开发过程中的常见跨域问题,还能有效提升系统的安全性。


衷心感谢您阅读至此,若您在本文中有所收获,恳请您不吝点赞、评论或分享,您的支持是我们持续创作高质量内容的动力源泉。同时,也诚挚邀请您关注本博客,以便获取更多前端开发与设计相关的深度解析和实战技巧,我们期待与您共同成长,一起探索前端世界的无限精彩!

相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
3天前
|
前端开发 JavaScript Java
计算机Java项目|基于Web的足球青训俱乐部管理后台系统的设计与开发
计算机Java项目|基于Web的足球青训俱乐部管理后台系统的设计与开发
|
5天前
|
传感器 小程序 搜索推荐
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
通过电子班牌设备和智慧校园数据平台的统一管理,在电子班牌上,班牌展示、学生上课刷卡考勤、考勤状况汇总展示,课表展示,考场管理,请假管理,成绩查询,考试优秀标兵展示、校园通知展示,班级文化各片展示等多种化展示。
29 0
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
|
12天前
|
关系型数据库 MySQL PHP
PHP的生命周期:从诞生到现代Web开发
本文将探索PHP的发展历程,从其最初的设计目标到成为现代Web开发的核心语言。我们将深入了解PHP如何适应不断变化的技术环境,并保持其在开发者社区中的受欢迎程度。
|
4天前
|
Dart 前端开发 JavaScript
Flutter for Web:跨平台移动与Web开发的新篇章
Flutter for Web是Google的开源UI工具包Flutter的延伸,用于构建高性能、高保真的跨平台应用,包括Web。它基于Dart语言和Flutter的核心框架,利用Skia渲染引擎通过WebAssembly在Web上运行。开发流程包括安装SDK、创建项目、编写Dart代码和部署。性能优化涉及减少渲染开销、代码压缩等。与传统Web框架相比,Flutter for Web在开发效率和性能上有优势,但兼容性和生态系统尚待完善。
11 0
|
5天前
|
JavaScript 前端开发 UED
在Web开发中,拖放(Drag and Drop)和动画效果是提升用户体验的重要工具
【6月更文挑战第12天】本文介绍了如何使用JavaScript实现拖放功能和基本动画效果。拖放功能通过监听mousedown、mousemove和mouseup事件,计算并更新元素位置实现。动画效果则利用requestAnimationFrame函数创建平滑移动的视觉效果。示例代码包括HTML结构和对应的JavaScript实现。
19 1
|
6天前
|
JSON 前端开发 Java
Go Web 开发 Demo【用户登录、注册、验证】(4)
Go Web 开发 Demo【用户登录、注册、验证】
|
6天前
|
存储 前端开发 中间件
Go Web 开发 Demo【用户登录、注册、验证】(3)
Go Web 开发 Demo【用户登录、注册、验证】
|
6天前
|
Go 数据库
Go Web 开发 Demo【用户登录、注册、验证】(2)
Go Web 开发 Demo【用户登录、注册、验证】
|
6天前
|
前端开发 数据库连接 Go
Go Web 开发 Demo【用户登录、注册、验证】(1)
Go Web 开发 Demo【用户登录、注册、验证】
|
8天前
|
前端开发 测试技术 数据库
Ruby on Rails:快速开发Web应用的秘密
【6月更文挑战第9天】Ruby on Rails,一款基于Ruby的Web开发框架,以其高效、简洁和强大备受青睐。通过“约定优于配置”减少配置工作,内置丰富功能库加速开发,如路由、数据库访问。活跃的社区和海量资源提供支持,MVC架构与RESTful设计确保代码清晰可扩展。高效的数据库迁移和测试工具保证质量。Rails是快速构建Web应用的理想选择,未来将持续影响Web开发领域。