前端跨域问题--解析与实战

引言

在现代网络应用中,跨域问题是一个常见的挑战。由于浏览器的同源策略,限制了从不同源(域名、协议或端口)进行资源共享,这就造成了跨域访问的限制。跨域资源共享(CORS)是一种技术,它允许网页上的脚本能够与不同源的服务器交互,是解决这一问题的关键技术。

跨域资源共享(CORS)简述

CORS 是一种网络安全协议,它定义了在服务器和客户端之间如何安全地实现跨源访问。通过在服务器端设置特定的HTTP头部,CORS 允许开发者指定哪些外部资源是可以被网页访问的,大幅度提升了网络应用的互操作性和安全性。

CORS 概念解析

什么是同源策略?

同源策略是浏览器的一项安全功能,它限制了一个源中的文档或脚本如何与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全措施,不允许不同源之间的读取数据。

CORS 是如何工作的?

CORS 通过在服务器端返回一系列 CORS 响应头来工作,如 Access-Control-Allow-Origin,这些头信息指示浏览器允许哪些网站通过脚本访问该服务器的资源。如果 CORS 头信息缺失或值不正确,浏览器将阻止任何跨源请求。

实现 CORS 的常用方法

使用 JSONP 解决跨域问题

JSONP(JSON with Padding)是一种早期用于绕过同源策略的技术,它通过动态添加 <script> 标签来请求一个带有回调函数的URL,从而实现跨域请求。这种方法只支持GET请求。

实现 CORS:基本概念和步骤

CORS 的实现涉及在服务器端设置适当的HTTP头。例如,Access-Control-Allow-Origin 可以被设置为特定的域名或星号(*),表示允许所有域名的跨域请求。

通过 Express.js 设置 CORS

基本 CORS 设置

在 Express.js 中,可以使用 cors 中间件来简化 CORS 的配置。例如,可以全局配置应用以接受来自某个特定源的请求:

const cors = require('cors');
app.use(cors({
    origin: 'http://example.com'
}));

高级 CORS 设置(携带凭证、允许多种 HTTP 方法等)

对于需要更复杂的 CORS 配置,如支持凭证或多种HTTP方法,可以详细配置 cors 中间件的选项:

app.use(cors({
    origin: 'http://example.com',
    methods: ['GET', 'POST'],
    credentials: true
}));

Node.js 项目实战演练

基础文件和目录结构

首先,创建以下目录和文件结构:

cross-origin-project/
│
├── public/
│   └── index.html
│
├── serverA.js
└── serverB.js
文件内容
  1. public/index.html - 这是服务 A 将托管的静态 HTML 文件,用于发起跨域请求。
  2. serverA.js - 这个文件包含了服务 A 的代码,用于托管静态页面。
  3. serverB.js - 这个文件包含了服务 B 的代码,用于提供 API 并处理 CORS。

服务 A:提供静态 HTML 页面

服务 A 托管静态 HTML 页面,允许用户通过按钮触发跨域请求。服务运行在端口 3001。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cross-Origin Example</title>
<script>
async function fetchData() {
    try {
        const response = await fetch('http://localhost:3002/data', {
            method: 'GET',
            credentials: 'include', // 启用凭证
            headers: {
                'X-Custom-Header': 'value' // 添加不被允许的头部
            }
        });
        const data = await response.json();
        document.getElementById('data').textContent = JSON.stringify(data);
    } catch (error) {
        console.error('Error:', error);
    }
}
</script>
</head>
<body>
<h1>Cross-Origin Resource Sharing (CORS) Test</h1>
<button onclick="fetchData()">Fetch Data</button>
<p id="data"></p>
</body>
</html>

将以下 JavaScript 代码保存到 serverA.js 文件中。这段代码配置了一个 Express.js 服务器来托管 public 目录下的静态文件。

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

// 提供静态文件
app.use(express.static('public'));

app.listen(3001, () => {
    console.log('Server A running on http://localhost:3001');
});

服务 B:提供 API 数据

将以下 JavaScript 代码保存到 serverB.js 文件中。这段代码创建了另一个 Express.js 服务器,它提供一个 API 端点并配置了 CORS 以允许来自服务 A 的跨域请求。

Node.js 配置(服务 B):

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

// 配置 CORS 策略
app.use(cors({
    origin: 'http://localhost:3001', // 允许来自 3001 端口的跨域请求
    methods: ['GET'],
    credentials: true, // 允许跨域请求包含凭证信息
    allowedHeaders: ['Content-Type', 'X-Custom-Header'] // 明确允许自定义头部
}));

app.get('/data', (req, res) => {
    const allowedOrigins = ['http://localhost:3001'];
    const origin = req.headers.origin;
    
    if (allowedOrigins.includes(origin)) {
        res.json({ message: 'Successfully fetched cross-origin data from server B.' });
    } else {
        res.status(403).send('Access denied');
    }
});

app.listen(3002, () => {
    console.log('Server B running on http://localhost:3002');
});

如何运行项目

  1. 打开命令行界面,并导航到 cross-origin-project 文件夹。
  2. 运行 npm init -y 来初始化 Node.js 项目,并通过 npm install express cors 安装必要的依赖。
  3. 在两个不同的命令行窗口中,分别启动服务 A 和服务 B:
    • 运行 node serverA.js 启动服务 A。
    • 运行 node serverB.js 启动服务 B。

访问 http://localhost:3001 在浏览器中查看 HTML 页面,并尝试发起跨域请求。此时应该能看到成功信息打印成功。

跨域原因列举

CORS(跨域资源共享)设置可能因为多种原因而失败,导致跨域请求无法成功。这些原因包括配置错误、环境限制或者浏览器的安全策略。下面是一些常见的原因导致跨域设置不成功:

1. 错误的源设置

如果 CORS 策略中设置的 Access-Control-Allow-Origin 头不正确,如不匹配请求的源(origin),跨域请求将被拒绝。例如,如果服务器只允许来自 http://localhost:3001 的请求,但请求实际来自 http://127.0.0.1:3001(尽管这两个地址指向同一个位置,但对 CORS 来说它们是不同的源)。

2. 忽略发送凭证

如果在 AJAX 请求中设置了 withCredentials = true,但服务器端的 CORS 策略没有正确设置 Access-Control-Allow-Credentials: true,则会导致跨域请求失败。同时,Access-Control-Allow-Origin 不能设置为 *Credentialstrue

3. 不支持的请求方法

如果请求使用了 CORS 策略中未明确允许的 HTTP 方法(如 PUT、PATCH、DELETE 等),请求也会被拒绝。只有正确声明了 Access-Control-Allow-Methods 头部,才能支持额外的方法。

4. 不允许的头部字段

如果跨域请求中包含了服务器未通过 Access-Control-Allow-Headers 明确允许的头部字段,请求将被浏览器拦截。这常见于自定义头部,如 X-Custom-Header

5. 预检请求失败

复杂请求(如带自定义头或者特定方法的请求)首先会发送一个预检(OPTIONS)请求,如果预检请求没有得到正确处理(如未返回允许的方法或头部),实际请求不会被发送。

6. 浏览器的安全策略

不同浏览器对于跨域请求的处理可能略有差异,有些浏览器的安全策略可能更加严格。此外,浏览器的某些配置或扩展程序(如广告拦截器或安全插件)可能阻止跨域请求。

7. 网络问题或服务器不可达

服务器配置正确,但由于网络问题或服务器宕机,导致请求无法到达服务器或服务器无法正确响应。

8. 错误的端口或协议

有时开发人员可能忽视了端口或协议的差异,这些细微的差别也会导致跨域错误,因为 CORS 是对协议、域名和端口都敏感的。

跨域行为实战

我们可以在先前给出的服务 A 和服务 B 的代码基础上,通过修改设置和观察结果来测试各种导致 CORS 设置不成功的情况。以下是针对每种情况的修改方法和预期的测试结果:

1. 错误的源设置

修改服务 B 来只接受来自 http://127.0.0.1:3001 的请求,而我们的请求实际上来自 http://localhost:3001

修改后的服务 B (api.js):

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

app.use(cors({
    origin: 'http://127.0.0.1:3001', // 错误的源设置
    methods: ['GET'],
    credentials: true
}));

app.get('/data', (req, res) => {
    res.json({ message: 'Successfully fetched cross-origin data from server B.' });
});

app.listen(3002, () => {
    console.log('Server B running on http://localhost:3002');
});

预期结果: 浏览器控制台将显示类似于 "No 'Access-Control-Allow-Origin' header is present on the requested resource" 的错误,表示请求的源不被允许。

2. 忽略发送凭证

删除或错误设置 Access-Control-Allow-Credentials,同时保留 credentials: 'include'

修改后的服务 B (api.js):

app.use(cors({
    origin: 'http://localhost:3001',
    methods: ['GET'],
    credentials: false // 错误地设置为 false
}));

预期结果: 浏览器控制台会显示错误,提示凭证不被允许,因为 credentials 属性需要服务器明确允许。

3. 不支持的请求方法

假设我们尝试发送一个 POST 请求,但服务 B 只允许 GET。

服务 A 发起 POST 请求 (public/index.html):

<script>
async function fetchData() {
    try {
        const response = await fetch('http://localhost:3002/data', {
            method: 'POST',
            credentials: 'include'
        });
        const data = await response.json();
        document.getElementById('data').textContent = JSON.stringify(data);
    } catch (error) {
        console.error('Error:', error);
    }
}
</script>

预期结果: 浏览器控制台会显示错误,指出使用了未被允许的方法。

4. 不允许的头部字段

发送包含自定义头部的请求,而服务 B 没有允许这个头部。

修改服务 A (public/index.html):

<script>
async function fetchData() {
    try {
        const response = await fetch('http://localhost:3002/data', {
            method: 'GET',
            credentials: 'include',
            headers: {
                'X-Custom-Header': 'value' // 添加不被允许的头部
            }
        });
        const data = await response.json();
        document.getElementById('data').textContent = JSON.stringify(data);
    } catch (error) {
        console.error('Error:', error);
    }
}
</script>

预期结果: 浏览器控制台将显示错误,提示 "Request header field X-Custom-Header is not allowed"。

通过这些修改和测试,你可以更好地理解 CORS 设置可能出现的问题和如何解决这些问题。每次修改后,确保重启服务并清空浏览器缓存,以确保测试结果的准确性。

服务端不做修改,浏览器如何避免cors

在 Web 开发中,浏览器的同源策略保护用户免受恶意网站的攻击,该策略禁止一个域的脚本与另一个域的资源进行交互。这意味着如果 CORS(跨源资源共享)策略不允许特定的跨源请求,那么在浏览器端通常没有简单的方法可以"避免"或"绕过" CORS 错误。这是一种安全机制,不应被绕过,特别是在生产环境中。

然而,对于开发测试目的,以下是几种常用的方法来处理或绕过浏览器的 CORS 限制:

1. 使用代理服务器

在开发环境中,可以设置一个代理服务器,它接收你的请求,向目标服务器发送请求,并将响应返回给你的应用。这种方式常用于前端开发中,例如使用创建 React 应用的 create-react-app 工具,可以在 package.json 中添加一个代理配置:

"proxy": "http://localhost:3002",

这样,所有对 /data 的请求将会被代理到 http://localhost:3002/data,而浏览器会认为这些请求仍然是同源的。

2. 使用浏览器插件

有些浏览器插件可以禁用或修改 CORS 策略,例如 "CORS Unblock" 等。这些插件通常用于开发和测试,但绝对不推荐在生产环境或浏览常规网站时使用,因为这会降低你的网络安全防护。

如何使用 CORS Unblock
步骤 1: 安装扩展
  1. Chrome 浏览器:

    • 打开 Chrome Web Store。
    • 在搜索框中输入 “CORS Unblock”。
    • 找到扩展,点击 “添加至 Chrome”。
  2. Firefox 浏览器:

    • 打开 Firefox Add-ons 网站。
    • 搜索 “CORS Unblock”。
    • 选择扩展并点击 “添加到 Firefox”。
步骤 2: 使用扩展

安装扩展后,你会在浏览器的工具栏中看到 CORS Unblock 的图标。你可以通过以下方式使用它:

  1. 激活/禁用 CORS Unblock:

    • 点击浏览器工具栏中的 CORS Unblock 图标。
    • 通常,扩展会有一个简单的开关按钮,允许你快速激活或禁用跨源请求限制。
    • 当扩展被激活时,图标通常会变色(例如变为绿色),表示现在跨源请求的限制被禁用。
  2. 刷新页面:

    • 在激活 CORS Unblock 后,刷新你正在工作的网页。现在,页面上的脚本应该能够发出并接收原本因 CORS 策略而被阻止的请求。
步骤 3: 监控和调试
  • 使用浏览器的开发者工具(通常可以通过右键点击页面并选择“检查”来打开)来监控网络请求和响应。
  • 检查网络标签,确保之前因 CORS 错误被阻止的请求现在是否成功。

3. 配置浏览器启动参数

对于 Chrome 浏览器,可以通过添加启动参数来禁用安全特性,这包括 CORS 检查。可以使用以下命令启动 Chrome(仅在本地开发时使用):

chrome.exe --disable-web-security --user-data-dir="C:/ChromeDevSession"

这将开启一个新的 Chrome 会话,其中禁用了跨域安全检查。注意,这种方法仅应在完全控制的开发环境中使用,且必须保证不会浏览任何潜在的恶意网站。

4.使用抓包工具

抓包工具是一类用于捕获、分析和修改计算机网络通信流量的软件工具。这些工具允许开发人员和网络管理员监控应用程序的网络交互,查看请求和响应的详细信息,进行性能评估,以及在开发和测试阶段修改数据流以进行调试。抓包工具对于诊断网络问题、优化性能和确保安全性都具有重要作用。常用的抓包工具有 「Fiddler」、「Charles」、「Wireshark」 等。

使用抓包工具代理请求的方式来处理跨域问题,通常涉及将 Web 网络请求通过工具进行中间代理,实现对请求和响应的监控、分析和修改。通过抓包工具的 rewrite 能力重写网络响应,给存在跨域的接口都添加上 CORS 相关配置,来解决跨域问题。

下面将简单介绍 Charles 工具的操作步骤:

「步骤一」:打开 Charles 工具栏 Tools --> Rewrite

「步骤二」:添加 Rewrite 配置

「步骤三」:Add 时添加 CORS 配置响应头

通过完成上述的三个步骤,我们现在就可以直接访问跨域接口了,可以看到所有的接口响应上都已经被添加了 Access-Control-Allow-Origin:* CORS 属性。

5. 修改服务器配置(理想方式)

虽然这不是浏览器端的解决方案,但修改服务器以发送正确的 CORS 头部是解决跨域问题的最佳实践。这包括正确配置 Access-Control-Allow-Origin 和相关的 CORS 头部。这是最安全和最可靠的解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/784894.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频融合共享平台视频共享融合赋能平台数字化升级医疗体系

在当前&#xff0c;医疗健康直接关系到国计民生&#xff0c;然而&#xff0c;由于医疗水平和资源分布不均&#xff0c;以及信息系统老化等问题&#xff0c;整体医疗服务能力和水平的提升受到了限制。视频融合云平台作为数字医疗发展的关键推动力量&#xff0c;在医疗领域的广泛…

大话C语言:第29篇 指针

1 指针概念 指针&#xff1a;地址的变量化形式&#xff0c;其存储的是内存中某个存储单元的地址。它是地址的数值表示。 指针变量&#xff1a;一种特殊的变量&#xff0c;它专门用于存放变量的地址&#xff08;即指针&#xff09;。 注意&#xff0c;指针和指针变量的区别&am…

【后端开发】docker安装MySQL并做端口映射

1.拉取MySQL镜像 docker pull mysql但是中途可能出现连接超时的情况 可以使用; docker pull do.nark.eu.org/library/mysql用国内镜像去拉取可能会快很多 2.启动容器并做端口映射 因为MySQL是在docker里面的所以要从docker外面连接MySQL需要做端口映射 以下是端口映射的的命…

python爬虫加入进度条

安装tqdm和requests库 pip install tqdm -i https://pypi.tuna.tsinghua.edu.cn/simplepip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple带进度条下载 import time # 引入time模块&#xff0c;用于处理时间相关的功能 from tqdm import * # 从tqdm包中…

【Java】搜索引擎设计:信息搜索怎么避免大海捞针?

一、内容分析 我们准备开发一个针对全网内容的搜索引擎&#xff0c;产品名称为“Bingoo”。 Bingoo的主要技术挑战包括&#xff1a; 针对爬虫获取的海量数据&#xff0c;如何高效地进行数据管理&#xff1b;当用户输入搜索词的时候&#xff0c;如何快速查找包含搜索词的网页…

YOLOv10改进 | EIoU、SIoU、WIoU、DIoU、FocusIoU等二十余种损失函数

一、本文介绍 这篇文章介绍了YOLOv10的重大改进&#xff0c;特别是在损失函数方面的创新。它不仅包括了多种IoU损失函数的改进和变体&#xff0c;如SIoU、WIoU、GIoU、DIoU、EIOU、CIoU&#xff0c;还融合了“Focus”思想&#xff0c;创造了一系列新的损失函数。这些组合形式的…

深度解密Spark性能优化之道课程

课程通过实战案例解析和性能调优技巧的讲解&#xff0c;帮助学员提升大数据处理系统的性能和效率。课程内容涵盖了Spark性能调优的各个方面&#xff0c;包括内存管理、并行度设置、数据倾斜处理、Shuffle调优、资源配置等关键技术和策略。学员将通过实际案例的演示和分析&#…

Caterpillar on a Tree

首先一个很显然的地方就是使用传送门肯定是在叶子节点使用&#xff0c;我们来考虑一下整个过程是怎么样的 为了方便&#xff0c;我们不妨假设可以传送回根节点\(k1\)次&#xff0c;然后要求最后回到根节点 我们先从根节点走到某一个叶子结点&#xff0c;然后再从这个叶子节点走…

Open3D 计算点云的平均密度

目录 一、概述 1.1基于领域密度计算原理 1.2应用 二、代码实现 三、实现效果 2.1点云显示 2.2密度计算结果 一、概述 在点云处理中&#xff0c;点的密度通常表示为某个点周围一定区域内的点的数量。高密度区域表示点云较密集&#xff0c;低密度区域表示点云较稀疏。计算…

Kubernetes基于helm部署jenkins

Kubernetes基于helm安装jenkins jenkins支持war包、docker镜像、系统安装包、helm安装等。在Kubernetes上使用Helm安装Jenkins可以简化安装和管理Jenkins的过程。同时借助Kubernetes&#xff0c;jenkins可以实现工作节点的动态调用伸缩&#xff0c;更好的提高资源利用率。通过…

拆分pdf文件最简单的方法,pdf怎么拆成一页一张

在数字化的时代&#xff0c;pdf文件已经成为我们日常办公、学习不可或缺的文档格式。然而&#xff0c;有时候我们可能需要对一个大的pdf文件进行拆分&#xff0c;以方便管理和分享。那么&#xff0c;如何将一个pdf文件拆分成多个pdf呢&#xff1f;本文将为你推荐一种好用的拆分…

HNTs-g-PEG-CDs-Biotin NPs;碳量子点修饰接枝生物素化的羟基磷灰石纳米管

HNTs-g-PEG-CDs-Biotin NPs&#xff0c;即碳量子点修饰接枝生物素化的羟基磷灰石纳米管&#xff0c;是一种结合了多种先进材料特性的纳米复合材料。以下是对该材料的详细分析&#xff1a; 一、组成成分及特性 羟基磷灰石纳米管&#xff08;HNTs&#xff09;&#xff1a; 羟基磷…

多用户挂售转卖竞拍闪拍商城系统/NFT数藏系统/后端PHP+前端UNIAPP源码带教程(亲测源码)

挂售转卖竞拍商城系统源码/竞拍系统/转拍闪拍系统/后端PHP前端UNiapp源码 亲测可用 1、后台管理&#xff1a;系统管理员通过后台可以轻松添加商品进行挂单。这包括商品的详细信息&#xff0c;如名称、描述、价格、库存等。 商品展示&#xff1a;挂单后的商品会在商城前端进行…

22.状态机设计--可乐机设计(投币三元出一瓶可乐)

理论知识&#xff1a; &#xff08;1&#xff09;状态机简写为FSM&#xff08;Finite State Machine&#xff09;&#xff0c;也称为同步有限状态机。同步是指状态的变化都是在时钟的边沿发送变化&#xff0c;有限值得是状态的个数是可数的。 &#xff08;2&#xff09;分类&…

Xilinx FPGA DDR4 接口的 PCB 准则

目录 1. 简介 1.1 FPGA-MIG 与 DDR4 介绍 1.2 DDR4 信号介绍 1.2.1 Clock Signals 1.2.2 Address and Command Signals 1.2.3 Address and Command Signals 1.2.4 Data Signals 1.2.5 Other Signals 2. 通用存储器布线准则 3. Xilinx FPGA-MIG 的 PCB 准则 3.1 引脚…

ElasticSearch第一天

学习目标&#xff1a; 能够理解ElasticSearch的作用能够安装ElasticSearch服务能够理解ElasticSearch的相关概念能够使用Postman发送Restful请求操作ElasticSearch能够理解分词器的作用能够使用ElasticSearch集成IK分词器能够完成es集群搭建 第一章 ElasticSearch简介 1.1 什么…

【Unity2D 2022:】制作NPC

一、创建NPC角色 1. 创建JambiNPC并同时创建Jambi站立动画 &#xff08;1&#xff09;点击第一张图片&#xff0c;按住shift不松&#xff0c;再选中后两张图片&#xff0c;拖到层级面板中 &#xff08;2&#xff09;将动画资源文件保存到Animation Clips文件夹中 &#xff08;…

YOLOv10改进 | 损失函数篇 | InnerIoU、InnerSIoU、InnerWIoU、FocusIoU等损失函数

一、本文介绍 本文给大家带来的是YOLOv10最新改进&#xff0c;为大家带来最近新提出的InnerIoU的内容同时用Inner的思想结合SIoU、WIoU、GIoU、DIoU、EIOU、CIoU等损失函数&#xff0c;形成 InnerIoU、InnerSIoU、InnerWIoU、等新版本损失函数&#xff0c;同时还结合了Focus和…

PHP源码:线上书店系统(附管理后台+前台)

一. 前言 今天小编给大家带来了一款可学习&#xff0c;可商用的&#xff0c;线上书店 源码&#xff0c;支持二开&#xff0c;无加密。项目的内容是销售书籍&#xff0c;可以扩展成pdf&#xff0c;文档等一些虚拟产品的销售。 详细界面和功能见下面视频演示。 二. 视频演示 线…

一个php文件怎么实现联系表单自动发送邮件

学习PHP&#xff1a;如何编写一个自动发送邮件的联系表单处理器&#xff1f; 无论是反馈意见、业务咨询&#xff0c;还是技术支持&#xff0c;联系表单都能为用户提供便捷的交流途径。AokSend将探讨如何通过一个PHP文件实现联系表单的自动发送邮件功能。 php文件&#xff1a;…