详细分析CORS 工作原理

🎯 CORS 是什么?

CORS 是一种安全机制,允许网页从不同的域(域名、协议、端口)请求资源。由于您的前端和后端部署在不同的域名上:

  • 前端:https://your-pages.pages.dev (Cloudflare Pages)
  • 后端:https://your-worker.workers.dev (Cloudflare Workers)

浏览器会阻止这种跨域请求,除非后端明确允许。

🔍 代码逐行分析

typescript 复制代码
export function handleCors(request: Request): Response | null {
  // 检查是否是 OPTIONS 请求(预检请求)
  if (request.method === 'OPTIONS') {
    // 如果是预检请求,返回一个空的响应和CORS头
    return new Response(null, {
      headers: {
        // 允许指定的前端域名进行跨域访问
        'Access-Control-Allow-Origin': 'https://your-pages.pages.dev',
        
        // 允许的HTTP方法
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
        
        // 允许的请求头
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
      },
    });
  }
  // 如果不是OPTIONS请求,返回null,让主流程继续处理
  return null;
}

🌐 CORS 工作原理

1. 预检请求 (OPTIONS)

当浏览器发送跨域请求时,会先发送一个 OPTIONS 请求来询问服务器是否允许实际请求。

示例流程:

复制代码
前端 (https://your-pages.pages.dev)
  → 发送 OPTIONS 预检请求到后端
  ← 后端返回 CORS 头
  → 浏览器检查通过后发送实际请求 (GET/POST)
  ← 后端返回实际数据

2. 实际请求

预检通过后,浏览器才会发送真正的请求(GET、POST等)。

🛠️ 改进建议

1. 动态允许域名(推荐)

typescript 复制代码
export function handleCors(request: Request): Response | null {
  // 允许的前端域名列表
  const allowedOrigins = [
    'https://your-pages.pages.dev',      // 生产环境
    'http://localhost:3000',             // 本地开发
    'http://localhost:5173'              // Vite 开发服务器
  ];
  
  const origin = request.headers.get('Origin');
  const allowedOrigin = allowedOrigins.includes(origin || '') ? origin : allowedOrigins[0];

  if (request.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': allowedOrigin || '*',
        'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With',
        'Access-Control-Allow-Credentials': 'true',
        'Access-Control-Max-Age': '86400', // 24小时缓存
      },
    });
  }
  return null;
}

2. 在实际响应中也添加CORS头

typescript 复制代码
// 在您的各个handler中,也需要添加CORS头
export function successResponse(data: any, message?: string): Response {
  return new Response(JSON.stringify({ success: true, data, message }), {
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': 'https://your-pages.pages.dev',
      'Access-Control-Allow-Credentials': 'true',
    },
  });
}

export function errorResponse(message: string, status: number = 500): Response {
  return new Response(JSON.stringify({ success: false, error: message }), {
    status,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': 'https://your-pages.pages.dev',
      'Access-Control-Allow-Credentials': 'true',
    },
  });
}

3. 完整的使用示例

typescript 复制代码
// src/index.ts
import { handleCors, successResponse } from './utils/response';

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    // 1. 首先处理CORS预检请求
    const corsResponse = handleCors(request);
    if (corsResponse) return corsResponse;

    // 2. 处理实际请求
    const url = new URL(request.url);
    
    if (url.pathname === '/api/test') {
      // 3. 在实际响应中也添加CORS头
      return successResponse({ message: 'Hello World' });
    }

    return new Response('Not found', { status: 404 });
  }
};

🔧 常见CORS头说明

头字段 说明 示例
Access-Control-Allow-Origin 允许的源 https://your-site.com
Access-Control-Allow-Methods 允许的HTTP方法 GET, POST, OPTIONS
Access-Control-Allow-Headers 允许的请求头 Content-Type, Authorization
Access-Control-Allow-Credentials 是否允许发送cookie true
Access-Control-Max-Age 预检请求缓存时间 86400 (秒)

💡 重要提示

  1. ** credentials **:如果前端需要发送cookie,需要设置 Access-Control-Allow-Credentials: true,并且 Access-Control-Allow-Origin 不能是通配符 *

  2. ** 生产环境配置 **:记得将 https://your-pages.pages.dev 替换为您实际的前端域名

  3. ** 本地开发 **:建议允许本地开发服务器的域名,方便调试

这段代码是确保您的前后端分离架构能够正常工作的关键!🚀

相关推荐
Linux运维技术栈2 个月前
企业级配置:Azure 邮件与 Cloudflare 域名解析的安全验证落地详解
运维·安全·flask·azure·cloudflare
技术管理修行2 个月前
【二】主流架构模式深度对比:单体、前后端分离与微服务
微服务·云原生·架构·服务发现·前后端分离·单体架构
编程乐学3 个月前
基于Android 开发完成的购物商城App--前后端分离项目
android·android studio·springboot·前后端分离·大作业·购物商城
耀耀_很无聊3 个月前
03_跨域问题解决
java·spring boot·跨域·satoken
_r0bin_3 个月前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
满怀10154 个月前
【Django全栈开发实战】从零构建企业级Web应用
前端·python·django·orm·web开发·前后端分离
小李李34 个月前
基于Node.js的Web爬虫: 使用Axios和Cheerio抓取网页数据
前端·爬虫·node.js·跨域
依旧风轻4 个月前
使用 DoH 查询域名 —— 以 core.tantanapp.com 为例的实战分析
ios·dns·cloudflare·doh·sqi
清风絮柳5 个月前
52.个人健康管理系统小程序(基于springboot&vue)
vue.js·spring boot·毕业设计·前后端分离·健康管理系统·个人健康管理系统·个人健康管理小程序