跳转到内容

HTML跨域资源共享 (CORS)

来自代码酷

HTML跨域资源共享 (CORS)[编辑 | 编辑源代码]

跨域资源共享(Cross-Origin Resource Sharing,简称CORS)是一种基于HTTP头的机制,允许服务器指示浏览器允许或拒绝来自不同源(域、协议或端口)的网页请求。它是现代Web开发中处理跨域请求的标准方式。

介绍[编辑 | 编辑源代码]

在Web开发中,出于安全考虑,浏览器会实施同源策略(Same-Origin Policy),限制来自不同源的脚本与资源交互。CORS提供了一种安全的方式,允许服务器声明哪些外部源可以访问其资源。

为什么需要CORS[编辑 | 编辑源代码]

  • 现代Web应用常常需要从多个域加载资源(如API、字体、图像)
  • 同源策略会阻止这些合法的跨域请求
  • CORS提供了一种标准化的方式来解决这个问题

基本概念[编辑 | 编辑源代码]

同源与不同源[编辑 | 编辑源代码]

两个URL在以下情况下被认为是同源

  • 相同的协议(http/https)
  • 相同的主机名(domain)
  • 相同的端口号

例如:

CORS工作原理[编辑 | 编辑源代码]

CORS通过HTTP头来实现跨域请求的控制。以下是CORS的基本流程:

sequenceDiagram Client->>Server: 发送跨域请求 (Origin头) Server-->>Client: 响应 (Access-Control-Allow-Origin头) alt 允许跨域 Client->>Server: 继续请求 else 拒绝跨域 Client->>Client: 阻止请求 end

简单请求[编辑 | 编辑源代码]

满足以下条件的请求被视为简单请求: 1. 使用GET、HEAD或POST方法 2. 仅包含安全的头(Accept、Accept-Language、Content-Language等) 3. Content-Type为application/x-www-form-urlencoded、multipart/form-data或text/plain

示例:

fetch('https://api.example.com/data', {
  method: 'GET',
  headers: {
    'Content-Type': 'text/plain'
  }
})
.then(response => response.json())
.then(data => console.log(data));

预检请求[编辑 | 编辑源代码]

不满足简单请求条件的请求会先发送一个OPTIONS方法的预检请求(Preflight Request),服务器确认允许后才会发送实际请求。

示例:

fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  },
  body: JSON.stringify({key: 'value'})
});

HTTP头详解[编辑 | 编辑源代码]

以下是CORS相关的主要HTTP头:

请求头[编辑 | 编辑源代码]

  • Origin: 指示请求的来源
  • Access-Control-Request-Method: 预检请求中声明实际请求的方法
  • Access-Control-Request-Headers: 预检请求中声明实际请求的自定义头

响应头[编辑 | 编辑源代码]

  • Access-Control-Allow-Origin: 指定允许访问资源的源
  • Access-Control-Allow-Methods: 指定允许的方法
  • Access-Control-Allow-Headers: 指定允许的头
  • Access-Control-Allow-Credentials: 指定是否允许发送凭据
  • Access-Control-Max-Age: 指定预检请求的缓存时间

服务器配置示例[编辑 | 编辑源代码]

Node.js (Express)[编辑 | 编辑源代码]

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

// 基本CORS配置
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

// 带凭证的CORS配置
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'https://trusted.example.com');
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

PHP[编辑 | 编辑源代码]

<?php
header("Access-Control-Allow-Origin: https://trusted.example.com");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
?>

实际应用场景[编辑 | 编辑源代码]

场景1:跨域API调用[编辑 | 编辑源代码]

前端应用(https://app.example.com)需要调用API(https://api.example.com

场景2:CDN资源访问[编辑 | 编辑源代码]

主站(https://www.example.com)需要从CDN(https://cdn.example.net)加载字体或脚本

场景3:微服务架构[编辑 | 编辑源代码]

多个服务部署在不同子域下需要相互通信

安全注意事项[编辑 | 编辑源代码]

  • 谨慎使用Access-Control-Allow-Origin: *,特别是涉及敏感数据时
  • 对于需要凭证的请求,必须指定具体的源而非通配符
  • 限制允许的方法和头,遵循最小权限原则
  • 考虑使用CSRF令牌等额外安全措施

常见问题[编辑 | 编辑源代码]

如何解决CORS错误?[编辑 | 编辑源代码]

1. 检查服务器是否正确设置了CORS头 2. 确保请求符合简单请求条件或正确处理了预检请求 3. 对于需要凭证的请求,设置credentials: 'include'(fetch API)或withCredentials: true(XHR)

JSONP与CORS有什么区别?[编辑 | 编辑源代码]

JSONP是早期解决跨域问题的技术,只支持GET请求,安全性较差。CORS是更现代、更安全的解决方案,支持所有HTTP方法。

高级主题[编辑 | 编辑源代码]

credentialed请求[编辑 | 编辑源代码]

需要发送cookie或HTTP认证信息的请求必须:

  • 服务器设置Access-Control-Allow-Credentials: true
  • Access-Control-Allow-Origin不能为*
  • 客户端设置withCredentials标志

预检请求缓存[编辑 | 编辑源代码]

通过Access-Control-Max-Age头可以减少不必要的预检请求。

总结[编辑 | 编辑源代码]

CORS是现代Web开发中处理跨域请求的标准机制。理解CORS的工作原理和配置方法对于开发需要跨域资源访问的Web应用至关重要。正确配置CORS既能满足功能需求,又能保障应用安全性。