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

引言

在现代网络应用中,跨域问题是一个常见的挑战。由于浏览器的同源策略,限制了从不同源(域名、协议或端口)进行资源共享,这就造成了跨域访问的限制。跨域资源共享(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.rhkb.cn/news/368663.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

九、函数的声明和定义

函数声明&#xff1a; 1. 告诉编译器有一个函数叫什么&#xff0c;参数是什么&#xff0c;返回类型是什么。但是具体是不是存在&#xff0c;函数 声明决定不了。 2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。 3. 函数的声明一般要放在头文件中的。 定义的函…

育才兴业,助力数字产业蓬勃发展

成都树莓集团通过校企合作、建设人才项目转化中心、推动一线多园战略以及提供全方位服务等举措&#xff0c;积极培养数字产业人才&#xff0c;为行业发展提供了有力支持。 一、校企合作&#xff0c;打造人才培养高地 树莓集团深知企业协同育人的重要性&#xff0c;积极与高校建…

某DingTalk企典 - Token

⚠️前言⚠️ 本文仅用于学术交流。 学习探讨逆向知识&#xff0c;欢迎私信共享学习心得。 如有侵权&#xff0c;联系博主删除。 请勿商用&#xff0c;否则后果自负。 网址 aHR0cHM6Ly9kaW5ndGFsay5jb20vcWlkaWFuLw 浅聊一下 没毛病&#xff0c;就这字段&#xff0c;有效期…

java考试题20道

选择题 编译Java源代码文件的命令是javac javac命令是将Java源代码文件进行编译得到字节码文件(.class文件) java命令是在JVM上运行得到的字节码文件 下面是一个示例&#xff1a; javac test.java -------> test.class java test ------> 运行test.class文件下列那…

#LinuxC高级 笔记二

makefile gcc gdb makefile 1. 分文件编程 1.1 源文件&#xff1a;.c结尾的文件 包含main函数的.c 包含子函数的.c 1.2 头文件&#xff1a;.h结尾的文件 头文件、宏定义、typedef 、结构体、共用体、枚举、函数声明 include引用时“”和<>的区别&#xff1a; <>去系…

复合机器人:手脚眼脑的完美结合

在现代工业制造的舞台上&#xff0c;复合机器人如同一位精密而高效的工匠&#xff0c;以其独特的手脚眼脑&#xff0c;正深刻改变着传统的生产方式。这些机器人不仅仅是机械臂的简单延伸&#xff0c;它们汇聚了先进的机械结构、智能的感知系统、精密的控制技术和灵活的思维能力…

【CSAPP】-linklab实验

目录 实验目的与要求 实验原理与内容 实验步骤 实验设备与软件环境 实验过程与结果&#xff08;可贴图&#xff09; 实验总结 实验目的与要求 1.了解链接的基本概念和链接过程所要完成的任务。 2.理解ELF目标代码和目标代码文件的基本概念和基本构成 3.了解ELF可重定位目…

安全和加密常识(6)Base64编码方式

文章目录 什么是 Base64编码原理编解码示例应用什么是 Base64 Base64 是一种用于将二进制数据编码为仅包含64种ASCII字符的文本格式的编码方法,注意,它不是加密算法。它设计的目的主要是使二进制数据能够通过只支持文本的传输层(如电子邮件)进行传输。Base64常用于在需要处…

Python | 基于支持向量机(SVM)的图像分类案例

支持向量机&#xff08;SVM&#xff09;是一种监督机器学习算法&#xff0c;可用于分类和回归任务。在本文中&#xff0c;我们将重点关注使用SVM进行图像分类。 当计算机处理图像时&#xff0c;它将其视为二维像素阵列。数组的大小对应于图像的分辨率&#xff0c;例如&#xf…

三菱PLC标签使用(I/O的映射)与内容

今天&#xff0c;小编继续开始三菱PLC的学习&#xff0c;今天的内容是标签及其标签的内容说明&#xff0c;如果对你有帮助&#xff0c;欢迎评论收藏。 标签的种类&#xff0c;等级&#xff0c;定义 种类 三菱3U的PLC的种类分别为二种&#xff1a;全局标签与局部标签 全局标签…

RabbitMQ-交换机的类型以及流程图练习-01

自己的飞书文档:‌‍‬‍‬‍​‍‬​⁠‍​​​‌⁠​​‬‍​​​‬‬‌​‌‌​​&#xfeff;​​​​&#xfeff;‍​‍​‌&#xfeff;⁠‬&#xfeff;&#xfeff;&#xfeff;​RabbitMQ的流程图和作业 - 飞书云文档 (feishu.cn) 作业 图片一张 画rabbit-mq 消息发…

【HDC.2024】探索无限可能:华为云区块链+X,创新融合新篇章

6月23日&#xff0c;华为开发者大会2024&#xff08;HDC 2024&#xff09;期间&#xff0c; “「区块链X」多元行业场景下的创新应用”分论坛在东莞松山湖举行&#xff0c;区块链技术再次成为焦点。本次论坛以"区块链X"为主题&#xff0c;集结了行业专家、技术领袖、…

深入解读:如何解决微调扩散模型时微调数据集和训练数据集之间的差距过大问题?

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;在微调扩散模型的时候经常会遇到微调数据集和训练数据集之间的差距过大&#xff0c;导致训练效果很差。在图像生成任务中并不明显&#xff0c;但是在视频生成任务中这个问题非常突出。这篇博客深入解读如何…

android应用的持续构建CI(一)-- 总体设计

一、背景 接下里我希望通过一系列的文章&#xff0c;把android应用的构建梳理一遍&#xff0c;从总体设计到逐个环节的实现。 总体设计jenkins集成手动签名依赖环境应用管理 二、构建流程图 三、技术组件 jenkinsjdkgradle360加固 既然是android应用的持续构建&#xff0c…

实验七 SQL数据更新和视图

题目 &#xff08;1&#xff09;向商品类别表category中插入一条记录&#xff08;801&#xff0c;‘座椅套’&#xff0c;‘各种品牌的汽车座套’&#xff09; &#xff08;2&#xff09;向商品表product中插入一条记录&#xff1a;商品编号80101&#xff0c;商品名称“四季通…

64.函数参数和指针变量

目录 一.函数参数 二.函数参数和指针变量 三.视频教程 一.函数参数 函数定义格式&#xff1a; 类型名 函数名(函数参数1,函数参数2...) {代码段 } 如&#xff1a; int sum(int x&#xff0c;int y) {return xy; } 函数参数的类型可以是普通类型&#xff0c;也可以是指针类…

文心一言 VS 讯飞星火 VS chatgpt (295)-- 算法导论21.4 4题

四、利用练习 21.4-2 &#xff0c;请给出一个简单的证明&#xff0c;证明在一个不相交集合森林上使用按秩合并策略而不使用路径压缩策略的运行时间为 O(m lgn) 。21.4-2 的内容是&#xff1a;“证明&#xff1a;每个结点的秩最多为 ⌊lgn⌋ 。”。如果要写代码&#xff0c;请用…

【C语言】auto 关键字

在C语言中&#xff0c;auto关键字用于声明局部变量&#xff0c;但它的使用已经变得很少见。事实上&#xff0c;从C99标准开始&#xff0c;auto关键字的默认行为就是隐含的&#xff0c;因此在大多数情况下无需显式使用它。 基本用法 在C语言中&#xff0c;auto关键字用于指定变…

CVPR 2024最佳论文:“神兵”的组合器 Generative Image Dynamics

CVPR 2024的最佳论文来自谷歌、美国加州大学圣迭戈分校。两篇都来至于视频生成领域&#xff0c;可见今年外界对视频生成领域关注度很高。今天的这篇是“Generative Image Dynamics”&#xff0c;Google Research发布的。它的研究成果令人震惊&#xff0c;从单张RGB图像生成连续…

DIY智能音箱:基于STM32的低成本解决方案 (附详细教程)

摘要: 本文详细介绍了基于STM32的智能音箱的设计与实现过程&#xff0c;包括硬件设计、软件架构、语音识别、音乐播放等关键技术。通过图文并茂的方式&#xff0c;结合Mermaid流程图和代码示例&#xff0c;帮助读者深入理解智能音箱的工作原理&#xff0c;并提供实际操作指导。…