当前位置: 首页 > news >正文

面试官:聊聊你知道的跨域解决方案

跨域是开发中经常会遇到的一个场景,也是面试中经常会讨论的一个问题。掌握常见的跨域解决方案及其背后的原理,不仅可以提高我们的开发效率,还能在面试中表现的更加游刃有余。


因此今天就来和大家从前端的角度来聊聊解决跨域常见的几种方式。

什么是跨域

在讲跨域之前,我们先来看看URL的组成内容:


一个URL的组成,通常包含协议、主机名、端口号、路径、查询参数和锚点几个部分。


这里展示了一个URL的示例:

https://www.example.com:8080/path/resource.html?page=1&sort=desc#header

在上述示例中:
● 协议为HTTPS
● 主机名为www.example.com
● 端口号为8080
● 路径为/path/resource.html
● 查询参数为page=1&sort=desc
● 锚点为header


所谓跨域,指的是请求URL中协议、主机名、端口号中任意一个部分不相同。


以上述URL为例,下面几种写法都算是和它跨域:

ttp://www.example.com:8080/    // 协议不同
https://www.example.a.com:8080/ // 主机名不同
https://www.example.com:8081/   // 端口号不同

为什么会跨域

其实跨域问题的出现是受限于浏览器的同源策略

所谓同源策略,其实是浏览器的一种安全机制,用于限制一个网页中的网络请求仅能够访问来自同一源(域名、协议和端口号均相同)的资源,主要目的是防止恶意网站通过脚本窃取其他网站的敏感数据,保障用户的隐私和安全。

当浏览器端的脚本(js文件)访问了其他域的网络资源时,就会出现跨域问题。

如何解决跨域

前文说到,跨域问题的出现是受限于浏览器的同源策略,那么常见的解决跨域问题的方案,其实也是围绕着浏览器展开的:

1.代理服务器

在我们平常的开发中,解决跨域问题最常使用的方案是使用代理服务器

代理服务器解决跨域问题其实是抓住了同源策略只受限于浏览器访问服务器,对于服务器访问服务器并没有限制的特点,作为中间服务器做了一个请求转发的功能

具体来说,就是前端工程师编写的网页运行在由webpack等脚手架搭建的代理服务器上,当前端网页在浏览器中发起网络请求时,其实这个请求是发送到代理服务器上的,然后代理服务器会将请求转发给目标服务器,再将目标服务器返回的响应转发给客户端。

代理服务器在此过程中扮演了一个中转的角色,可以对请求和响应进行一些修改、过滤和拦截,以实现一些特定的功能。因为前端网页运行在代理服务器上,所以不存在跨域问题。

那么在线上环境和开发环境下,代理服务器是如何做请求转发的呢?

1.线上环境

在线上环境下,我们一般会采用nginx来做反向代理,从而把前端的请求转发到目标接口上。

nginx是一个轻量级高并发的web服务器,基于事件驱动,而且跨平台,window和Linux都可以进行配置。

它作为代理服务器来解决开发中的跨域问题的主要方法就是监听线上前端网址的运行端口,然后碰到包含特殊标记的请求后就进行请求转发

2.开发环境

在开发环境下,无论是借助于webpack还是使用vite或其他脚手架搭建的前端项目,解决跨域问题的核心是借助http-proxy-middleware中间件实现的。而http-proxy-middleware中间件的核心又是对http-proxy的进一步封装。

这里先展示一下在项目中使用http-proxy-middleware来实现请求转发功能的示例代码:

const { createProxyMiddleware } = require('http-proxy-middleware');module.exports = {server: {proxy: {// 将 /api/* 的请求代理到 http://localhost:3000/*'/api': {target: 'http://localhost:3000',changeOrigin: true,pathRewrite: { '^/api': '/' }}}}
};

接着我们可以自己使用原生node,借助http-proxy库来搭建一个具有请求转发功能的代理服务器Demo,感兴趣的朋友可以自己测试玩玩

1. 首先需要创建一个空文件夹(全英命名)作为项目文件夹,然后使用npm init -y命令将项目升级为node的项目:

npm init -y

2. 接着在项目根目录下创建一个index.html文件用于发起跨域请求:

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>请求转发测试</title>
</head><body><h1>请求转发测试</h1><p id="message"></p><script>fetch('/api/login').then(response => response.text()).then(data => {document.getElementById('message').textContent = data;});</script>
</body></html>

3. 接着在项目根目录下新建index.js文件来编写服务端的代码。
index.js文件是实现具有请求转发功能的代理服务器的核心文件。

const http = require('http');
const httpProxy = require('http-proxy');
const fs = require('fs');
const path = require('path');// 创建代理服务器实例
const proxy = httpProxy.createProxyServer({});// 创建HTTP服务器
const server = http.createServer((req, res) => {if (req.url === '/' || req.url.endsWith('.html')) {// 读取HTML文件const filename = path.join(__dirname, 'index.html');fs.readFile(filename, 'utf8', (err, data) => {if (err) {res.writeHead(500);res.end('Error reading HTML file');} else {res.writeHead(200, { 'Content-Type': 'text/html' });res.end(data);}});} else if (req.url.startsWith('/api')) {// 重写路径,替换跨域关键词req.url = req.url.replace(/^\/api/, '');// 将请求转发至目标服务器proxy.web(req, res, {target: 'http://localhost:3000/',changeOrigin: true,});    }
});// 监听端口
server.listen(8080, () => {console.log('Server started on port 8080');
});

4. 接着编写目标服务器target.js文件的内容,用于测试跨域访问:

const http = require('http');const server = http.createServer((req, res) => {if (req.url.startsWith('/login')) {res.writeHead(200, { 'Content-Type': 'text/plain' });res.end('我是localhost主机3000端口下的方法,恭喜你访问成功!');} else {res.writeHead(200, { 'Content-Type': 'text/plain' });res.end('Hello, world!');}
});server.listen(3000, () => {console.log('Target server is listening on port:3000');
})

5. 打开终端,输入启动目标服务器的命令:

node ./target.js //项目根目录下执行

6. 再开一个终端启动代理服务器,等待浏览器端发起请求就可以啦:

node ./index.js //项目根目录下执行

7. 最后在浏览器里访问http://localhost:8080, 打开控制台即可查看效果:

可以发现,浏览器network模块的网络请求确实是访问的8080端口的方法,但是我们的服务器默默的做了请求转发的功能,并将请求转发获取到的内容返回到了前端页面上。

其实http-proxy是对node内置库http的进一步封装,网络请求的核心部分还是使用http创建一个服务器对象去访问的。感兴趣的同学可以再读读http-proxy的源码~

除了代理服务器这种绕过浏览器同源策略的解决方式外,从前端的角度解决跨域问题还有如下一些常见的方法:

1.借助JSONP

JSONP的原理是通过动态创建<script>标签,向服务器发送请求并在请求URL中传递一个回调函数名(通常是在本地定义的函数名),服务器在返回的数据中将这个回调函数名和实际数据一起封装成一个JavaScript函数的调用,返回给客户端,客户端利用该回调函数对数据进行处理。

JSONP之所以能够跨域请求数据,是因为浏览器对于<script>标签的请求不会受到同源策略的限制。

需要注意的是,使用JSONP技术的前提是服务器需要支持JSONP的方式,即在返回的数据中包含回调函数名和实际数据的封装,否则客户端无法处理返回的数据。

此外,JSONP只支持GET请求,不支持POST等其他HTTP请求方式,因为<script>标签只支持GET请求。

因此JSONP这种方式在我们的开发中使用的场景不多。

2.使用CORS

CORS全称为Cross-Origin Resource Sharing,它通过HTTP头部信息告诉浏览器哪些跨域请求是被允许的,从而实现安全的跨域访问。

CORS解决跨域需要浏览器端和服务器端的配合。原理是在服务器端设置HTTP头部信息,告诉浏览器允许哪些源(域名、协议、端口)访问服务器上的资源,如果请求的源不在允许的列表中,则浏览器将拒绝访


问。

服务器可以通过设置Access-Control-Allow-OriginAccess-Control-Allow-HeadersAccess-Control-Allow-Methods等HTTP头部信息来控制跨域访问权限。

具体地,当浏览器发起跨域请求时,会先发送一个OPTIONS请求(预检请求),询问服务器是否允许该跨域请求。

服务器接收到该请求后,根据请求中的HTTP头部信息判断是否允许该请求。

如果允许,则返回相应的HTTP头部信息告知浏览器可以继续发送真正的跨域请求。如果不允许,则返回一个错误状态码,告诉浏览器该请求被拒绝。

预检请求时,请求头常见参数有

请求头
Origin表示请求的源地址,即发起跨域请求的域名
Access-Control-Request-Method表示实际请求采用的HTTP方法
Access-Control-Request-Headers表示实际请求中所携带的额外请求头信息,比如自定义请求头等

预检请求时,响应头常见参数有

响应头
Access-Control-Allow-Origin*、origin…
Access-Control-Allow-HeadersPOST, GET, PUT, DELETE, OPTIONS
Access-Control-Allow-MethodsContent-Type, Authorization…
Access-Control-Allow-Credentialstrue
Access-Control-Max-Age86400

需要注意的是,使用CORS的前提是服务器需要设置相关的HTTP头部信息,且浏览器支持CORS。此外,CORS只支持现代浏览器,对于一些老旧的浏览器可能不支持CORS。

3.其他方案

比如WebSocketpostMessage等等


总结

近年来,随着前后端技术的飞速发展,前后端独立开发逐渐成为主流的开发模式。前后端程序员只需约定好接口,然后独自进行相应模块的开发,最后进行接口联调即可。在接口联调过程中,开发环境下的跨域就是一个需要解决的问题。


除此之外,当前后端项目打包上云后,前端页面通过线上地址访问后台接口时,线上环境下的跨域也是一个需要解决的问题。


本文讲述了几种常见的跨域解决方案,这些方案各有优缺点,大家可以根据实际情况选择适合的方案来解决对应的跨域问题~

相关文章:

面试官:聊聊你知道的跨域解决方案

跨域是开发中经常会遇到的一个场景&#xff0c;也是面试中经常会讨论的一个问题。掌握常见的跨域解决方案及其背后的原理&#xff0c;不仅可以提高我们的开发效率&#xff0c;还能在面试中表现的更加游刃有余。 因此今天就来和大家从前端的角度来聊聊解决跨域常见的几种方式。…...

SpringCloud五大核心组件

Consul 等&#xff0c;提供了搭建分布式系统及微服务常用的工具&#xff0c;如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性token、全局锁、选主、分布式会话和集群状态等&#xff0c;满足了构建微服务所需的所有解决方案。 服务发现——Netflix Eureka …...

Verilog HDL语言入门(二)

强烈建议用同步设计2.在设计时总是记住时序问题3.在一个设计开始就要考虑到地电平或高电平复位、同步或异步复位、上升沿或下降沿触发等问题&#xff0c;在所有模块中都要遵守它4.在不同的情况下用if和case&#xff0c;最好少用if的多层嵌套&#xff08;1层或2层比较合适&#…...

Simpleperf详细使用

一、Simpleperf介绍 Simpleperf是一个强大的命令行工具&#xff0c;它包含在NDK中&#xff0c;可以帮助我们分析应用的CPU性能。Simpleperf可以帮助我们找到应用的热点&#xff0c;而热点往往与性能问题相关&#xff0c;这样我们就可以分析修复热点源。 如果您更喜欢使用命令…...

【算法基础】二分图(染色法 匈牙利算法)

一、二分图 1. 染色法 一个图是二分图,当且仅当,图中不含奇数环。在判别一个图是否为二分图⑩,其实相当于染色问题,每条边的两个点必须是不同的颜色,一共有两种颜色,如果染色过程中出现矛盾,则说明不是二分图。 for i = 1 to n:if i 未染色DFS(i, 1); //将i号点染色未…...

Caputo 分数阶微分方程-慢扩散方程初边值问题基于L1 逼近的空间二阶方法及其Matlab程序实现

2.3.3 Caputo 分数阶一维问题基于 L1 逼近的空间二阶方法 考虑如下时间分数阶慢扩散方程初边值问题 { 0 C D t α u ( x , t ) = u...

I.MX6ULL_Linux_驱动篇(29) GPIO驱动

Linux 下的任何外设驱动&#xff0c;最终都是要配置相应的硬件寄存器。所以本篇的 LED 灯驱动最终也是对 I.MX6ULL 的 IO 口进行配置&#xff0c;与裸机实验不同的是&#xff0c;在 Linux 下编写驱动要符合 Linux 的驱动框架。I.MX6U-ALPHA 开发板上的 LED 连接到 I.MX6ULL 的 …...

jupyter的安装和使用

目录 ❤ Jupyter Notebook是什么&#xff1f; notebook jupyter 简介 notebook jupyter 组成 网页应用 文档 主要特点 ❤ jupyter notebook的安装 notebook jupyter 安装有两种途径 1.通过Anaconda进行安装 2.通过pip进行安装 启动jupyter notebook ❤ jupyter …...

Springboot新手开发 Cloud篇

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏&#xff1a;后端专栏 &#x1f4e7;如果文章知识点有错误的地方&#xff0c;…...

Linux:函数指针做函数参数

#include <stdio.h> #include <stdlib.h> //创建带有函数指针做参数的函数框架api //调用者要先实现回调函数 //调用者再去调用函数框架 //所谓的回调是指 调用者去调用一个带有函数指针做参数的函数框架&#xff0c;函数框架反过来要调用调用者提供的回调函数 …...

Vue3(递归组件) + 原生Table 实现树结构复杂表格

一、递归组件 什么是递归&#xff0c;Javascript中经常能接触到递归函数。也就是函数自己调用自己。那对于组件来说也是一样的逻辑。平时工作中见得最多应该就是菜单组件&#xff0c;大部分系统里面的都是递归组件。文章中我做了按需引入的配置&#xff0c;所以看不到我引用组…...

ArrayList底层源码解析

Java源码系列&#xff1a;下方连接 http://t.csdn.cn/Nwzed 文章目录前言一、**ArrayList底层结构和源码分析**无参构造调用创建ArrayList集合无参构造总结&#xff1a;发文3个工作日后 up 会把总结放入前言部分&#xff0c;但也诚邀读者总结&#xff0c;可放入评论区有参构造…...

python:DIY字符画的程序使用说明.doc

目录开发环境要求运行方法具体的操作步骤如下&#xff1a;代码示例源码及运行程序下载地址开发环境要求 本系统的软件开发及运行环境具体如下。 操作系统&#xff1a;Windows 7、Windows 10。 Python版本&#xff1a;Python 3.7.0。 开发工具&#xff1a;Python IDLE。 …...

【Python/Opencv】图像权重加法函数:cv2.addWeighted()详解

【Python/Opencv】图像权重加法函数&#xff1a;cv2.addWeighted()详解 文章目录【Python/Opencv】图像权重加法函数&#xff1a;cv2.addWeighted()详解1. 介绍2. API3. 代码示例与效果3.1 代码3.2 效果4. 参考1. 介绍 在OpenCV图像加法cv2.add函数详解详细介绍了图像的加法运…...

容器的老祖宗LXC和Docker的关系

一、什么是LXC&#xff1f; LXC&#xff08;Linux Container的缩写&#xff09;是一个基于Linux内核的容器虚拟化技术&#xff0c;它提供了一种轻量级、快速、简便的方式来创建和管理系统容器。与传统虚拟化技术不同&#xff0c;LXC并不会模拟硬件&#xff0c;而是利用Linux内…...

Webpack迁移Rspack速攻实战教程(前瞻版)

前言 rspack 即将开源&#xff0c;但社区中不乏有已经落地的 case &#xff0c;比如 rspack-migration-showcase 、 modern.js 等。 基于此&#xff0c;本文将介绍如何迁移一个近似于 CRA&#xff08; create-react-app &#xff09; 的项目到 rspack 。 在阅读本文前&#…...

一行代码“黑”掉任意网站

文章目录只需一行代码&#xff0c;轻轻一点就可以把任意网站变成暗黑模式。 首先我们先做一个实验&#xff0c;在任意网站中&#xff0c;打开浏览器开发者工具(F12)&#xff0c;在 C1onsole 控制台输入如下代码并回车&#xff1a; document.documentElement.style.filterinve…...

51单片机入门 -驱动 8x8 LED 点阵屏

硬件型号、软件版本、以及烧录流程 操作系统&#xff1a;Windows 10 x84-64单片机&#xff1a;STC89C52RC编译器&#xff1a;SDCC烧录软件&#xff1a;stcgal 1.6开发板&#xff1a;普中51单片机开发板A2套件&#xff08;2022&#xff09; 在 VS Code 中新建项目到烧录的过程…...

Xinlinx zynq7045国产替代 FMQL45T900全国产化 ARM 核心板+扩展板

TES745D 是一款基于 FMQL45T900 的全国产化 ARM 核心板。该核心板将 FMQL45T900&#xff08;与XC7Z045-2FFG900I 兼容&#xff09;的最小系统集成在了一个 87*117mm 的核心板上&#xff0c;可以作为一个核心模块&#xff0c;进行功能性扩展&#xff0c;能够快速的搭建起一个信号…...

硬刚ChatGPT!文心一言能否为百度止颓?中国版ChatGPT“狂飙”的机会在哪儿?

文章目录目录产品背景发展历程科技简介主要功能合作伙伴结语文心一言 &#xff08;英文名&#xff1a;ERNIE Bot&#xff09; *是百度基于文心大模型技术推出的生成式对话产品&#xff0c;被外界誉为“中国版ChatGPT”&#xff0c;将于2023年3月份面向公众开放。 [40] 百度在人…...

Python 异步: 在非阻塞子进程中运行命令(19)

动动发财的小手&#xff0c;点个赞吧&#xff01; 我们可以从 asyncio 执行命令。该命令将在我们可以使用非阻塞 I/O 写入和读取的子进程中运行。 1. 什么是 asyncio.subprocess.Process asyncio.subprocess.Process 类提供了由 asyncio 运行的子进程的表示。它在 asyncio 程序…...

蓝桥杯嵌入式第五课--输入捕获

前言输入捕获的考题十分明确&#xff0c;就是测量输入脉冲波形的占空比和频率&#xff0c;对我们的板子而言&#xff0c;就是检测板载的两个信号发生器产生的信号&#xff1a;具体来说就是使用PA15和PB4来做输入捕获。输入捕获原理简介输入捕获能够对输入信号的上升沿和下降沿进…...

Spring事务和事务传播机制

目录 Spring中事务的实现 1、通过代码的方式手动实现事务 2、通过注解的方式实现声明式事务 2.1、Transactional作用范围 2.2、Transactional参数说明 2.3、注意事项 2.4、Transactional工作原理 事务隔离级别 1、事务特性 2、Spring中设置事务隔离级别 2.1、MySQL事…...

基于OpenCV+CUDA实时视频抠绿、背景合成以及抠绿算法小结

一、关于抠绿 百度百科上描述抠绿“抠绿是指在摄影或摄像时,以绿色为背景进行拍摄,在后期制作时使用特技机的“色键”将绿色背景抠去,改换其他更理想的背景的技术。”绿幕的使用已经非常普遍,大到好莱坞大片,小到自媒体的节目,一些商业娱乐场景,几乎都用使用。但是很多非…...

MySQL 中的 UNION 语句

文章目录一、数据准备一、UNION 和 UNION ALL二、UNION 的执行顺序&#xff08;UNION 和其他语句一同出现&#xff09;三、MySQL 使用 UNION&#xff08;ALL&#xff09; ORDER 导致排序失效四、UNION 报错语法一、数据准备 -- 创建表 CREATE TABLE test_user (ID int(11) NO…...

高完整性系统工程(三): Logic Intro Formal Specification

目录 1. Propositions 命题 2.1 Propositional Connectives 命题连接词 2.2 Variables 变量 2.3 Sets 2.3.1 Set Operations 2.4 Predicates 2.5 Quantification 量化 2.6 Relations 2.6.1 What Is A Relation? 2.6.2 Relations as Sets 2.6.3 Binary Relations as…...

【linux】多线程概念详述

文章目录一、线程基本概念1.1 进程地址空间与页表1.2 页表结构1.3 线程的理解1.3.1 如何描述线程1.4 再谈进程1.5 代码理解1.5.1 原生库提供线程pthread_create1.6 资源共享问题1.7 资源私有问题二、总结2.1 什么是线程2.2 并行与并发2.3 线程的优点2.4 线程的缺点2.5 线程异常…...

【Java】P8 面向对象(3)方法 基本知识

面向对象 方法方法方法的声明权限修饰符返回值类型方法名形参列表方法体简单案例方法 方法 是对类或对象行为特征的抽象&#xff0c;用来完成某个功能的操作。方法的目的 是为了实现代码复用&#xff0c;减少冗余&#xff0c;简化代码&#xff1b;方法不能独立存在&#xff0c…...

js中null和undefined的区别

js中null和undefined的区别?这也是一个常见的js面试题 相同点 1&#xff0c;都是基本类型。 2&#xff0c;做判断值都是false。 !!null false // true !!undefined false // true不同点 1&#xff0c;诞生时间null在前&#xff0c;undefined在后。因为js作者Brendan-Eic…...

【Linux】linux中的c++怎么调试?gdb的介绍和使用。

背景1.1.前提知识程序的发布方式有两种&#xff0c;debug模式和release模式Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须在源代码生成二进制程序的时候, 加上 -g 选项windows上的调试方法有区别吗&#xff1f;1.调试思路是一样的2…...

给公司做的东西放到私人网站上/seo网站关键词排名快速

在网上总看到有人说STM32的硬件IIC不好用&#xff0c;可到底哪不好用&#xff0c;也一直没找到问题点。 最近有空看了一下STM32的硬件IIC&#xff0c;里面很多EV5/EV6等事件的概念是有些别扭&#xff0c;不过不影响使用。 写了一个简单的polling模式下的数据读写&#xff0c;也…...

卸载wordpress插件/宣传网站有哪些

写在前面的话 和很多朋友一样&#xff0c;我一直坚持写技术方面的博客&#xff0c;希望通过这样的方式&#xff0c;一方面沉淀自己的知识结构和心得体会&#xff0c;更希望也许能够在某些时候给其他一些朋友提供一些参考帮助。我自己这么多年的技术道路&#xff0c;每每遇到一些…...

做自己的网站需要会编程吗/新闻发布

修改图片的大小 点击图像&#xff0c;图像大小 本文转自 烂泥行天下 51CTO博客&#xff0c;原文链接&#xff1a;http://blog.51cto.com/ilanni/580885...

aje网站润色/网络营销运营公司

前一段时间开发需要经常使用 pip 下载&#xff0c;虽然把 pip 源改成了国内源&#xff0c;但我对速度还是不满意&#xff0c;更为重要的是集成测试环境是离线的&#xff0c;要在集成测试环境开发显然需要搭建自己的本地 pip 源。在使用 devpi 之前我曾使用过 pip2pi&#xff0c…...

php+mysql网站开发教程/seo什么意思

转载于CentOS中文站&#xff1a;http://www.centoscn.com/CentOS/Intermediate/2013/0817/1334.html一、MySQL安装Centos下安装mysql 请点开:http://www.centoscn.com/CentosServer/sql/2013/0817/1285.html二、MySQL的几个重要目录MySQL安装完成后不象SQL Server默认安装在一个…...

烟台建设/廊坊seo网络推广

androidAndroid活动生命周期&#xff0c;如果是Android Developer访谈中最常被问到的问题之一。 它也是一个容易搞砸的人。 您必须已经从developer.android.com和许多android开发书籍中看到了此活动生命周期图。 资料来源&#xff1a;developer.android.com但这还不够。 该图仅…...