[ 跨域问题 ] 前后端以及服务端 解决跨域的各种方法

这篇文章主要介绍了跨域问题,包括其定义、产生原因及各种解决方法。原因是浏览器安全策略限制,方法有 JSONP、CORS、Domain、 postMessage、Nginx配置、.NetCore配置。

 前言

什么是跨域问题?

在Web应用中,当一个网页的脚本试图去请求另一个域名下的资源时,就会遇到跨域问题。跨域问题是由浏览器的同源策略所引起的。换句话说:后端返回给浏览器的数据会被浏览器的同源策略给拦截下来。

同源策略要求资源的协议、域名和端口号都必须相同,才能确保数据的安全性。如果不满足这个条件,请求将被浏览器拒绝,从而导致跨域问题的出现。

  • 同源策略: 协议号-域名-端口号 都相同的地址,浏览器才认为是同源
协议号:域名:端口号 / 路径https://192.168.31.45:8080/userhttps://192.168.31.45:8080/list

上面这个例子虽然它们的路径不一样但是协议号、域名、端口号都相同,所以它们就是同源的

跨域问题的原因?

跨域问题主要是由于浏览器的安全策略限制引起的。同源策略的目的是保护用户的隐私和数据安全,防止恶意网站获取用户的敏感信息或进行未授权的操作。 通过限制跨域请求,浏览器有效地减少了许多网络攻击的风险,例如跨站脚本攻击(XSS)和跨站请求伪造(CSRF)。

JSONP

JSONP(JSON with Padding)是一种用于解决跨域请求的技术,它利用了 <script> 标签可以跨域加载资源的特性。

下面是 JSONP 解决跨域请求的基本原理:

  1. 前端发起 JSONP 请求: 前端页面通过动态创建 <script> 标签,设置其 src 属性为包含回调函数的 URL。通常这个 URL 是指向另一个域名下的服务器接口。

  2. 服务端返回数据: 服务端接收到 JSONP 请求后,会将数据包装在回调函数中返回给前端。这样前端页面就可以获得跨域请求返回的数据。

  3. 前端处理数据: 前端页面定义好与回调函数同名的 JavaScript 函数,当服务端返回数据时,会执行这个函数并传入返回的数据作为参数,从而实现跨域数据的获取和处理。

前端代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="btn">获取数据</button><script>// 定义一个函数 jsonp,用于发送 JSONP 请求function jsonp(url, cb) {return new Promise((resolve, reject) => {// 创建一个 script 标签const script = document.createElement('script');// 设置 script 的 src 属性,包含了请求的 URL 和回调函数名称script.src = `${url}?cb=${cb}`; // http://localhost:3000?cb='callback'// 将 script 添加到文档中document.body.appendChild(script); // 浏览器自动请求 src 中的内容// 定义一个全局函数,用于处理返回的数据window[cb] = (data) => {resolve(data)}})}// 获取按钮元素let btn = document.getElementById('btn');// 绑定点击事件btn.addEventListener('click', () => {// 发送 JSONP 请求jsonp('http://localhost:3000', 'callback').then(res => {console.log('后端的返回结果:' + res);})})</script>
</body>
</html>

后端代码:

const Koa = require('koa');
const app = new Koa();// 定义中间件函数 main,处理请求并返回数据
const main = (ctx, next) => {console.log(ctx.query); // 输出请求参数对象 { cb: 'callback' }// 从请求参数中获取回调函数名称const cb = ctx.query.cb;// 准备要返回给前端的数据const data = '给前端的数据';// 构造带有回调函数名称的字符串,格式为 'callback("给前端的数据")'const str = `${cb}('${data}')`;// 将构造好的字符串作为响应体返回给前端ctx.body = str;
}// 将 main 中间件注册到 Koa 应用中
app.use(main);// 监听 3000 端口,启动服务器
app.listen(3000, () => {console.log('listening on port 3000');
})

优点:

  1. 简单易用: JSONP 实现简单,只需在前端添加一个 <script> 标签即可完成跨域请求,无需复杂的配置。
  2. 兼容性好: JSONP 能够兼容各种浏览器,包括早期版本的浏览器,因为它是通过动态创建 <script> 标签实现的。
  3. 支持跨域请求: JSONP 可以在不同域之间进行数据通信,解决了传统 AJAX 请求受同源策略限制的问题。

缺点:

  1. 安全性问题: JSONP 存在安全风险,因为它是通过在前端动态加载脚本来获取数据,可能会被用于注入恶意脚本,导致安全漏洞。
  2. 只支持 GET 请求: JSONP 只能发起 GET 请求,无法支持其他类型的 HTTP 请求,如 POST、PUT 等。
  3. 依赖服务端支持: JSONP 需要服务端返回数据时将其包裹在一个回调函数中,因此需要服务端提供支持,如果服务端不支持 JSONP 格式返回数据,则无法使用该方法。

CORS(跨域资源共享)

CORS是一种机制,允许服务器在响应中携带一个特殊的标头,以告知浏览器该服务器允许哪些源的网页访问其资源。 可以总结为一句话:后端通过设置响应头来告诉浏览器不要拒绝接受后端的响应。

前端代码:在用户点击按钮时,通过发送跨域请求获取服务器返回的数据,并将数据打印到浏览器的控制台

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><button id="btn">获取数据</button><script>let btn = document.getElementById('btn');btn.addEventListener('click', () => {fetch('http://localhost:3000')  // 发送跨域请求到服务器.then(res => res.json()).then((res) => {console.log(res);  // 打印返回的数据到控制台})})</script>
</body>
</html>

代码实现了以下功能:

  1. 在 HTML 中定义了一个按钮元素,id 为 "btn",用于触发发送数据请求。
  2. 在 JavaScript 部分,使用 fetch 函数发送 GET 请求到指定的服务器地址 "http://localhost:3000"。
  3. 在成功接收到服务器响应后,使用 .then 方法将响应解析为 JSON 格式。
  4. 在第二个 .then 方法中,处理解析后的数据,并将其输出到浏览器的控制台。

后端代码 :Node.js 服务器代码,创建了一个 HTTP 服务器,监听在端口 3000。当接收到请求时,返回一个包含 "hello cors" 消息的 JSON 数据。

const http = require('http');const server = http.createServer((req, res) => {res.writeHead(200, {// cros实现原理'Access-Control-Allow-Origin': 'http://127.0.0.1:5500'  // 允许来自指定地址的跨域请求})let data = {msg: "hello cors"}res.end(JSON.stringify(data)) // 返回数据给前端页面
})server.listen(3000, () => {console.log('listening on port 3000');
})

后端代码第6行在服务端设置响应头来控制跨域访问

常见的响应头包括:

  • Access-Control-Allow-Origin:指定允许访问的域名。

  • 例如,Access-Control-Allow-Origin: *表示允许所有域名访问,

  • Access-Control-Allow-Origin:'http://127.0.0.1:5500'表示只允许特定域名访问。

  • Access-Control-Allow-Methods:指定允许的HTTP方法。

  • Access-Control-Allow-Headers:指定允许的自定义请求头。

CORS支持各种类型的HTTP请求,包括GET、POST等。

Domain

我们还可以使用 Domain 方法来解决一些特定情况下的跨域访问问题。 在跨域通信时,还需要注意以下几点:

  1. 页面的域名必须满足 Domain 方法的限制,即二级域名相同(如 example.com)。

  2. 父级页面需要在设置 document.domain 之前定义需要共享的变量或对象。

  3. 子级页面可以通过 window.parent 来访问父级页面的属性或变量,但需要确保父级页面已经加载完成并且两者的域名设置已生效。

下面举一个简单的例子来说明 Domain 方法的用法:

假设有两个页面分别位于不同子域名下,一个是 parent.example.com,另一个是 child.example.com。我们希望这两个页面能够进行跨域通信。

在父级页面 parent.example.com/index.html 中的代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Parent Page</title>
</head>
<body><h1>Parent Page</h1><iframe src="http://child.example.com/child.html"></iframe><script>document.domain = 'example.com';var messageFromParent = 'Hello from parent page!';</script>
</body>
</html>

在子级页面 child.example.com/child.html 中的代码如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Child Page</title>
</head>
<body><h1>Child Page</h1><script>document.domain = 'example.com';var messageFromChild = 'Hello from child page!';// 访问父级页面定义的变量var message = window.parent.messageFromParent;console.log('Message from parent: ' + message);</script>
</body>
</html>

在这个例子中,父级页面和子级页面分别设置了相同的 document.domain 为 'example.com',以实现二级域名相同。

父级页面定义了一个名为 messageFromParent 的变量,子级页面在加载后通过 window.parent 来访问父级页面定义的变量,并打印出父级页面的消息。

通过设置相同的 document.domain,父子页面之间就可以进行跨域通信,实现数据共享和交互。

postMessage

使用 postMessage() 方法结合 <iframe> 元素可以实现跨域通信,这是一种常见的技术。通过在父窗口和嵌套的 <iframe> 之间使用 postMessage() 方法,可以安全地在不同源之间进行通信。

<iframe> 可以用于解决跨域通信的问题,其原理是利用浏览器中同源策略的限制,将不同域的内容加载到独立的 <iframe> 中,通过 postMessage 方法进行跨文档通信。

在 a.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h2>a.html</h2><!-- 创建一个 iframe 元素来加载 b.html --><iframe src="http://127.0.0.1:5500/postMessage/b.html" frameborder="0" id="iframe"></iframe><script>// 向 b.html 发送数据let iframe = document.getElementById('iframe');iframe.onload = function() {// 准备要发送的数据let data = {name: 'Tom'};// 通过 postMessage 方法向 iframe 发送数据iframe.contentWindow.postMessage(JSON.stringify(data), 'http://127.0.0.1:5500');}// 监听来自 b.html 的消息window.addEventListener('message', function(e) {console.log(e.data);});</script>
</body>
</html>

在 b.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h4>b.html</h4><script>// 监听来自父页面的消息window.addEventListener('message', function(e) {console.log(JSON.parse(e.data));if (e.data) {// 收到消息后延迟 2 秒发送回应给父页面setTimeout(function() {window.parent.postMessage('我接受到', 'http://127.0.0.1:5500');}, 2000);}});</script>
</body>
</html>

优点:

  • 安全性:  使用 <iframe> 结合 postMessage 进行跨域通信是一种相对安全的方法,能够避免常见的跨站脚本攻击(XSS)。
  • 灵活性:  可以在不同域之间传递数据,实现更丰富的交互体验,如单点登录、共享数据等。
  • 适用性广泛:  跨域通信是 Web 开发中常见需求,而 <iframe> 结合 postMessage 是一种通用且有效的解决方案。

缺点:

  • 复杂性:  跨域通信涉及到多个文档之间的交互,需要额外的处理和编码,增加了开发的复杂度。
  • 性能开销:  使用 <iframe> 进行跨域通信可能会引入额外的网络请求和资源加载,对页面加载性能有一定影响。
  • 兼容性:  旧版本的浏览器可能对 postMessage 支持不完整,需要做兼容性处理。

Nginx 

nginx反向代理 配置 

这个配置允许任何域通过GET、POST和OPTIONS方法访问资源,并且允许一些常见的头信息字段。Access-Control-Max-Age 指令用于指定预检请求的结果能被缓存多久。

确保在实际部署时,根据安全和需求情况将Access-Control-Allow-Origin设置为特定域,而不是*(表示允许所有域),以减少跨站脚本攻击(XSS)的风险。

server {listen 80;server_name example.com;location / {# 设置允许跨域的域,* 表示允许任何域,也可以设置特定的域add_header 'Access-Control-Allow-Origin' '*';# 允许的方法add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';# 允许的头信息字段add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type';# 缓存时间add_header 'Access-Control-Max-Age' 1728000;# 其他配置...}# 其他 server 配置...
}

.NetCore

在.NET Core中配置跨域非常简单。你可以在Startup.cs文件中的ConfigureServices方法添加跨域服务,并在Configure方法中配置跨域。

public class Startup
{// ...// 在ConfigureServices方法中添加跨域服务public void ConfigureServices(IServiceCollection services){// ...services.AddCors(options =>{options.AddPolicy("CorsPolicy",builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());});}// 在Configure方法中配置跨域public void Configure(IApplicationBuilder app, IWebHostEnvironment env){// ...// 使用跨域策略app.UseCors("CorsPolicy");// ...}
}

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

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

相关文章

【软考】系统架构设计师-信息安全技术基础

信息安全核心知识点 信息安全5要素&#xff1a;机密性、完整性、可用性、可控性、审查性 信息安全范围&#xff1a;设备安全、数据安全、内容安全、行为安全 网络安全 网络安全的隐患体现在&#xff1a;物理安全性、软件安全漏洞、不兼容使用安全漏洞、选择合适的安全哲理 …

SQL Server Management Studio 的JDBC驱动程序和IDEA 连接

一、数据库准备 &#xff08;一&#xff09;启用 TCP/IP 协议 操作入口 首先&#xff0c;我们要找到 SQL Server 配置管理器&#xff0c;操作路径为&#xff1a;通过 “此电脑” 右键选择 “管理”&#xff0c;在弹出的 “计算机管理” 窗口中&#xff0c;找到 “服务和应用程…

类和对象——static 成员,匿名对象(C++)

1.static成员 a&#xff09;⽤static修饰的成员变量&#xff0c;称之为静态成员变量&#xff0c;静态成员变量⼀定要在类外进行初始化。 b&#xff09;静态成员变量为所有类对象所共享&#xff0c;不属于某个具体的对象&#xff0c;不存在对象中&#xff0c;存放在静态区。 …

游戏引擎学习第17天

视频参考:https://www.bilibili.com/video/BV1LPUpYJEXE/ 回顾上一天的内容 1. 整体目标&#xff1a; 处理键盘输入&#xff1a;将键盘输入的处理逻辑从平台特定的代码中分离出来&#xff0c;放入更独立的函数中以便管理。优化消息循环&#xff1a;确保消息循环能够有效处理 …

【JavaEE初阶 — 多线程】线程池

目录 1. 线程池的原理 1.1 为什么要有线程池 1.2 线程池的构造方法 1.3 线程池的核心参数 1.4 TimeUnit 1.5 工作队列的类型 1.6 工厂设计模式 1.6.1 工厂模式概念 1.6.2 使用工厂模式的好处 1.6.3 使用工厂模式的典型案例 1.6.4 Thread…

基于Vue+SpringBoot的求职招聘平台

平台概述 本平台是一个高效、便捷的人才与职位匹配系统&#xff0c;旨在为求职者与招聘者提供一站式服务。平台内设三大核心角色&#xff1a;求职者、招聘者以及超级管理员&#xff0c;每个角色拥有独特的功能模块&#xff0c;确保用户能够轻松完成从信息获取到最终录用的整个…

黑马点评 秒杀下单出现的问题:服务器异常---java.lang.NullPointerException: null(已解决)

前言&#xff1a; 在此之前找了好多资料&#xff0c;查了很多&#xff0c;都没有找到对应解决的方法&#xff0c;虽然知道是userid为空&#xff0c;但不知道要修改哪里&#xff0c;还是自己的debug能力不足&#xff0c;以后得多加练习。。。 问题如下&#xff1a; 点击限时抢…

使用GDB或Delve对已经运行起来的Go程序进行远程调试

同步发布在我的博客&#xff0c;欢迎来点赞。 使用 GDB 或 Delve 对已经运行起来的 Go 程序进行远程调试 使用 GDB 或 Delve 对已经运行起来的 Go 程序进行远程调试 背景 Java 程序可以很方便地通过 jdwp 参数指定一个对外端口进行远程调试&#xff0c;如 java \ -agentlib…

如何解决pdf.js跨域从url动态加载pdf文档

摘要 当我们想用PDF.js从URL加载文档时&#xff0c;将会因遇到跨域问题而中断&#xff0c;且是因为会触发了PDF.js和浏览器的双重CORS block&#xff0c;这篇文章将会介绍&#xff1a;①如何禁用pdf.js的跨域&#xff1f;②如何绕过浏览器的CORS加载URL文件&#xff1f;②如何使…

Jmeter中的断言(三)

9--MD5Hex断言 功能特点 数据完整性验证&#xff1a;验证响应数据的 MD5 哈希值是否符合预期。简单配置&#xff1a;只需提供预期的 MD5 哈希值即可。灵活配置&#xff1a;可以设置多个断言条件&#xff0c;满足复杂的测试需求。 配置步骤 添加 MD5Hex 断言 右键点击需要添加…

Tomcat和Nginx原理说明

Tomcat Tomcat 是一个开源的 Java 应用服务器&#xff0c;它由多个关键组件组成。这些组件共同协作&#xff0c;实现了 Servlet 容器的功能。以下是 Tomcat 的核心组件说明及其逻辑架构的示意图。 1. Tomcat 核心组件说明 (1) Server 描述&#xff1a;Tomcat 的顶级组件&…

vmWare虚拟环境centos7安装Hadoop 伪分布式实践

背景&#xff1a;近期在研发大数据中台&#xff0c;需要研究Hadoop hive 的各种特性&#xff0c;需要搭建一个Hadoop的虚拟环境&#xff0c;本来想着使用dock &#xff0c;但突然发现docker 公共仓库的镜像 被XX 了&#xff0c;无奈重新使用vm 搭建虚拟机。 大概经历了6个小时完…

10 基于深度学习的目标检测

首次完成时间&#xff1a;2024 年 11月 20 日 1. 使用OpenCV的dnn模块实现图像分类。 1&#xff09;程序代码&#xff1a; import numpy as np import cv2# 解析标签文件 row open("model1/synset_words.txt").read().strip().split("\n") class_label …

ssl证书,以 Nginx 为例

文章目录 1 证书概述1.1 常见证书格式1.2 证书的几种扩展名1.3 关于 PKCS#12 格式 2 Nginx 下证书配置2.1 证书的工作原理2.1.1 单向认证2.1.2 双向认证 2.2 CA 机构签发2.2.1 免费 SSL 证书申请2.2.2 双向认证 2.3 自签证书2.3.1 单向认证2.3.2 双向认证 附录 1&#xff1a;Wi…

android:taskAffinity 对Activity退出时跳转的影响

android:taskAffinity 对Activity跳转的影响 概述taskAffinity 的工作机制taskAffinity对 Activity 跳转的影响一个实际的开发问题总结参考 概述 在 Android 开发中&#xff0c;任务栈&#xff08;Task&#xff09;是一个核心概念。它决定了应用程序的 Activity 如何相互交互以…

专家PID控制

专家PID控制&#xff08;Expert PID Control&#xff09;是一种结合了传统PID控制和专家系统思想的控制方法。它通过引入专家经验、规则和推理机制&#xff0c;以改善PID控制器在面对复杂系统时的性能。专家PID控制不仅仅依赖于固定的PID参数&#xff08;比例、积分、微分&…

ES分词环境实战

文章目录 安装下载1.1 下载镜像1.2 单节点启动 防火墙设置异常处理【1】iptable链路中断 参考文档 参加完2024年11月软考&#xff0c;对ES的分词进行考查&#xff0c;前期有【 Docker 环境下安装部署 Elasticsearch 和 kibana】和【 Docker 环境下为 Elasticsearch 安装IK 分…

【桌面应用程序】Vue-Electron 环境构建、打包与测试(Windows)

前言 Vue 与 Electron 环境构建、打包与测试。 目录 前言 一、基本环境准备 二、配置npm源 三、创建Vue项目 四、添加Electron支持 五、应用启动 ​六、添加UI框架 ElementUI ​七、打包 一、基本环境准备 npm版本&#xff1a;8.6.0node版本&#xff1a;v18.0.0Vue/…

golang中的init函数

程序的初始化和执行都起始于 main 包。如果 main 包还导入了其它的包&#xff0c;那么就会在编译时将它们依次 导入。有时一个包会被多个包同时导入&#xff0c;那么它只会被导入一次&#xff08;例如很多包可能都会用到 fmt 包&#xff0c;但 它只会被导入一次&#x…

Paint 学习笔记

目录 ippaint 外扩对象 LCM_inpaint_Outpaint_Comfy&#xff1a; 不支持文字引导 ippaint https://github.com/Sanster/IOPaint 外扩对象 https://www.iopaint.com/models/diffusion/powerpaint_v2 GitHub - open-mmlab/PowerPaint: [ECCV 2024] PowerPaint, a versatile …