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

引言

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

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

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

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

相关文章

如何无线连接ios,自动化稳定

如果你的iPhone的USB端口无法使用&#xff0c;但你需要进行自动化测试或其他操作&#xff0c;可以通过无线连接来实现。无线连接通常涉及到使用Wi-Fi网络&#xff0c;这样你就可以在不使用USB线的情况下与设备交互。以下是一些可以考虑的方法&#xff1a; 1.使用Xcode进行无线…

William Yang:从区块链先锋到艺术平台创始人

在区块链技术和加密货币市场飞速发展的今天&#xff0c;William Yang无疑是这一领域的佼佼者。他不仅在学术和媒体领域取得了显著成就&#xff0c;更在创业之路上不断探索&#xff0c;成为了业内知名的KOL&#xff08;关键意见领袖&#xff09;。今天&#xff0c;我们有幸采访到…

AI姓氏头像生成微信小程序系统源码

&#x1f525;【科技新潮流】AI姓氏头像生成系统&#xff0c;你的专属个性新名片&#xff01;&#x1f389; &#x1f31f; 开篇惊艳&#xff1a;一键解锁你的姓氏魅力 ✨ Hey小伙伴们&#xff0c;今天我要安利一个超酷炫的科技小玩意——AI姓氏头像生成系统&#xff01;是不…

js字符串序列化为二进制数据

在JavaScript中&#xff0c;可以通过不同的方式将字符串序列化为二进制数据。以下是几种常见的方法&#xff1a; TextEncoder 和 TextDecoder JavaScript 提供了 TextEncoder 和 TextDecoder 对象&#xff0c;可以用来处理字符串和二进制数据之间的转换。 // 将字符串转换为二进…

MySQL Server时区支持

本文介绍MySQL维护的时区设置——如何加载命名时间支持所需的系统表&#xff0c;如何及时了解时区变化&#xff0c;以及如何启用闰秒支持。 从MySQL 8.0.19开始&#xff0c;插入的日期时间值也支持时区偏移。 1 时区变量 MySQL Server维护了几个时区设置&#xff1a; 服务器…

爬虫笔记20——票星球抢票脚本的实现

以下内容仅供交流学习使用&#xff01;&#xff01;&#xff01; 思路分析 前面的爬虫笔记一步一步走过来我们的技术水平也有了较大的提升了&#xff0c;现在我们来进行一下票星球抢票实战项目&#xff0c;实现票星球的自动抢票。 我们打开票星球的移动端页面&#xff0c;分…

视频字幕提取在线工具有哪些?总结5个字幕提取工具

平时在沉浸式追剧的时候&#xff0c;我们常常都会被影视剧中的各种金句爆梗而逗得开怀大笑~而真正要用到时候却总是一片头脑空白。其实要记住它们最好的办法便是将其提取留档下来&#xff0c;每次有需要的时候打开就能一下子回顾到~ 今天就来带大家盘一盘视频字幕提取的软件好…

高考假期预习指南

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

目标检测YOLO实战应用案例100讲-基于深度学习的无人机影像小目标识别

目录 前言 研究现状 深度学习研究现状 目标检测研究现状 目标检测存在的问题 2 基于深度学习的目标检测算法理论基础 2.1 卷积神经网络 2.1.1 卷积层 2.1.2 池化层 2.1.3 激活函数 2.1.4 全连接层 2.2 优化器 2.3 基于深度学习的目标检测算法 2.3.1 …

树上差分的公式推导

今天写了一道题目&#xff0c;需要采用线段树合并树上差分来解决 题目链接&#xff1a;P1600 [NOIP2016 提高组] 天天爱跑步 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 其实当时已经想到要用这两种方法&#xff0c;但苦于一直找不到转移方程&#xff0c;最后看了答案才领…

java中可变参数

在Java中&#xff0c;... 是可变参数&#xff08;varargs&#xff09;的语法&#xff0c;用于允许一个方法接受可变数量的参数。可变参数的引入使得方法调用更加灵活和简洁。以下是对可变参数的详细解释和使用示例。 可变参数的定义和使用 定义&#xff1a; 在方法参数列表中…

22-Pandas日期时间格式化

Pandas日期时间格式化 当进行数据分析时&#xff0c;我们会遇到很多带有日期、时间格式的数据集&#xff0c;在处理这些数据集时&#xff0c;可能会遇到日期格式不统一的问题&#xff0c;此时就需要对日期时间做统一的格式化处理。比如“Wednesday, June 6, 2020”可以写成“6…

Rust: polars行遍历,从dataframe到struct及Bar设计比较

pandas提供了iterrows()、itertuples()、apply等行遍历的方式&#xff0c;还是比较方便的。 polars的列操作功能非常强大&#xff0c;这个在其官网上有详细的介绍。由于polars底层的arrow是列存储模式&#xff0c;行操作效率低下&#xff0c;官方也不推荐以行方式进行数据操作。…

react_后台管理_项目

目录 1.运行项目 2. 项目结构 ①项目顶部导航栏 ②项目左侧导航栏 ③主页面-路由切换区 本项目使用的是 reacttsscss 技术栈。 1.运行项目 在当前页面顶部下载本项目&#xff0c;解压后使用编辑器打开&#xff0c;然后再终端输入命令&#xff1a; npm i 下载依赖后&am…

【应急响应】Windows应急响应 - 基础命令篇

前言 在如今的数字化时代&#xff0c;Windows系统面对着越来越复杂的网络威胁和安全挑战。本文将深入探讨在Windows环境下的实战应急响应策略。我们将重点关注实际应急响应流程、关键工具的应用&#xff0c;以及如何快速准确地识别和应对安全事件。通过分享实际案例分析&#…

FIO压测磁盘性能以及需要注意的问题

一、压测类型 1、顺序读&#xff08;IO&#xff09;&#xff1a;read&#xff0c;bs1M&#xff0c;job数从1开始往上加&#xff1a;2、3、4... 2、顺序写&#xff08;IO&#xff09;&#xff1a;write&#xff0c;bs1M&#xff0c;job数从1开始往上加&#xff1a;2、3、4... …

如何通过 1688 商品详情的 API 接口获取商品的详细信息

在当今数字化商业的大背景下&#xff0c;能够从 1688 这样规模庞大且商品种类丰富的电商平台中准确、高效地获取商品的详细信息&#xff0c;对于众多企业和开发者而言&#xff0c;具有举足轻重的意义。而通过 1688 商品详情的 API 接口来实现这一目标&#xff0c;无疑是一种强大…

【ACM出版,马来西亚-吉隆坡举行】第四届互联网技术与教育信息化国际会议 (ITEI 2024)

作为全球科技创新大趋势的引领者&#xff0c;中国不断营造更加开放的科技创新环境&#xff0c;不断提升学术合作的深度和广度&#xff0c;构建惠及各方的创新共同体。这是对全球化的新贡献&#xff0c;是构建人类命运共同体的新贡献。 第四届互联网技术与教育信息化国际学术会议…

【 木兰宽松许可证】

木兰宽松许可证&#xff0c; 第1版 2019年8月 http://license.coscl.org.cn/MulanPSL 您对“软件”的复制、使用、修改及分发受木兰宽松许可证&#xff0c;第1版&#xff08;“本许可证”&#xff09;的如下条款的约束&#xff1a; 定义 “软件”是指由“贡献”构成的许可在“本…

【C++知识点总结全系列 (07)】:模板与泛型编程详细总结与分析

模板与泛型编程 1、概述(1)What&#xff08;什么是模板、泛型编程&#xff09;(2)Why(3)Which(4)模板参数A.WhatB.HowC.模板参数的类型成员D.默认模板参数 2、模板函数3、模板类(1)How&#xff08;如何定义和使用模板类&#xff09;(2)成员模板 4、模板实参推断(1)What&#xf…