跨域+四种解决方法
文章目录
- 一、跨域
- 二、JSONP实现跨域请求
- 三、前端代理实现跨域请求
- 四、后端设置请求头实现跨域请求
- 五、Nginx代理实现跨域请求
- 5.1 安装Nginx软件
- 5.2 使用Ubuntu安装nginx
本文是在学习课程满神yyds后记录的笔记,强烈推荐读者去看此课程。
一、跨域
出于浏览器的同源策略限制,浏览器会拒绝跨域请求。
什么是同源策略?
请求的时候拥有相同的协议、域名、端口,只要有一个不同就属于跨域。
主机(http://www.small5.com) | 是否跨域 | 原因 |
---|---|---|
https://www.small5.com | 是 | 协议不同 http和https |
http://www.small5.com:8001 | 是 | 端口不同 80 和 8001 |
http://www.baidu.com | 是 | 域名不同 small5和百度 |
http://www.small5.com/index.html | 否 | 协议、端口、域名全部相同 |
跨域的四种解决方案:
- 前后端协商jsoup
- 前端解决 使用代理dev
- 后段解决 设置请求头
- 运维端解决 nginx代理
二、JSONP实现跨域请求
jsonp解决跨域的原理是:由于script标签的src属性不受同源策略的限制,可以跨域请求到服务器端的资源,并且把资源作为脚本(js)来运行,因此可以解决跨域。
img属性也有src属性,但是它只是把服务器的资源返回,并没有进一步做任何js的动作。
但是jsonp解决跨域存在一个限制:它只能发送get请求。
JSONP解决跨域的基本工作原理:
- 前端定义一个回调函数,该函数将处理从服务器返回的数据
- 前端创建一个script标签,并将跨域请求的url作为script标签的src属性值,在url中,需要包含一个特殊的参数,该参数用来告知服务器回调函数的名称,后端服务器会通过query拿到回调函数名。
- 服务器接收到请求后,解析url参数,通过query拿到回调函数名,并响应请求:将要发送的数据作为参数传入回调函数返回前端【使用模板字符串调用前端函数】
- 前端接收到响应后,由于脚本标签生成的script元素的src属性已经指向了服务器返回的脚本url,浏览器会自动执行该脚本,从而调用前端所定义的回调函数,并将服务器返回的数据作为参数传入。
可以看出使用JSONP解决跨域需要前后端相互配合实现。
下面我们通过代码实现JSONP实现跨域访问:
前端html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>jsonp实现跨域</title>
</head><body><script>// jsonp函数实现了跨域访问,,其中包括1.定义script并设置src传递回调函数名 2.前端window中动态定义回调函数// name表示回调函数名const jsonp = (name) => {// 2.前端创建一个script标签,并将跨域请求的url作为script标签的src属性值,// 在url中,需要包含一个特殊的参数,该参数用来告知服务器回调函数的名称,后端服务器通过query拿到回调函数名let script = document.createElement('script')script.src = 'http://localhost:3000/api/jsonp?callback=' + name // 将回调函数名传递给服务器document.body.appendChild(script)return new Promise((resolve) => {// 1.前端动态定义一个回调函数,该函数将处理从服务器返回的数据window[name] = (data) => { // data是后端调用前端回调函数返回的数据// 4. 返回服务器返回的数据resolve(data)}console.log(window);})}// 调用jsonp方法// 这里的回调函数名为callback加时间戳 使用时间戳的原因是避免函数重名jsonp(`callback${new Date().getTime()}`).then(res => {// 输出服务器返回的数据console.log(res);})</script>
</body></html>
后端使用node,index.js
const express = require('express')const app = express()
// 发送get请求
app.get('/api/jsonp', (req, res) => {// 3. 服务器接收到请求后,解析url参数,通过query拿到回调函数名,并发送请求:将要发送的数据作为参数传入回调函数const { callback } = req.query// 后端响应请求并返回数据// 注意这里以模板字符串的形式返回数据,实现调用前端的回调函数,传递了值为hello small5的参数,并执行这个前端回调函数// 实际上这个参数的内容才是真实响应数据,改变参数内容,前端收到的数据也随之改变res.send(`${callback}('hello small5')`)
})app.listen(3000, () => {console.log('server is running');
})
运行端口为3000的服务器
通过Live Server运行html文件,Live Server会自动开一个5500的端口,这和服务器端口不一致,因此是存在跨域的。
通过上图,可以看到使用JSONP实现跨域请求的请求结果,状态码是200,表示请求成功并响应结果,这表明使用JSONP成功实现了跨域请求。
下面我们来看看请求传递的参数和响应结果以验证:
可以看到前端成功传递参数值为callback+时间戳的回调函数名、参数名为callback的参数,以及响应结果是调用此回调函数并传参。
下面我们再看看前端输出的请求结果:
可以看到前端成功接收响应的数据,下面我们通过输出的window来验证是否有一个名为callback+时间戳的回调函数
可以看到完全符合预期,前端确实存在名为callback+时间戳的回调函数。
以上就是JSONP实现跨域请求的所有内容。
三、前端代理实现跨域请求
前端使用代理来实现跨域请求需要借助前端构建工具,如webpack、rollup、vite之类构建工具,通过在配置文件中配置代理,实现拦截请求并转发到指定服务器上。
这里我以vite来举例:
使用npm i vite -D
安装vite,并在根目录新建vite.config.js
文件。
vite.config,js
import { defineConfig } from 'vite'export default defineConfig({server: {proxy: {'/api': {target: 'http://localhost:3000',changeOrigin: true, // changeOrigin表示是否改变请求的源// rewrite: (path)=>path.replace(/^\/api/, '') // rewrite表示重写请求路径,这里的示例实现了匹配到/api/则替换为空}}}
})
node配置服务器:index.js
const express = require('express')const app = express()// 返回json数据的get请求
app.get('/api/json', (req, res) => {res.json({name: 'small5'})
})app.listen(3000, () => {console.log('server is running');
})
html文件发送请求:index.html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>jsonp解决跨域</title>
</head><body><script>// Fetch 是一个基于 promise 的用于浏览器和 node.js 的 HTTP 客户端,// 它能够轻松的将请求发送到服务器并得到响应。// Fetch 使用方式简单,又能充分发挥出 Promise 的特性,是越来越多人使用的发起请求的方式之一。fetch('/api/json').then(res => res.json()).then(res => {console.log(res);})</script>
</body></html>
这里我们就不能使用Live Server运行html文件了,需要配置一下pacage.json文件,使用vite运行html文件。
{"scripts": {"dev": "vite"},"dependencies": {"express": "^4.17.1","express-session": "^1.17.3",},"devDependencies": {"vite": "^4.4.8"}
}
现在我们使用npm run dev
命令运行:
可以看到vite自动开了url为http://127.0.0.1:5173
客户端域名,这和node后端定义的http://localhost:3000
是存在跨域的。查看请求结果如下:
可以看到状态码200,表示成功实现了跨域请求,再看看接口响应结果和前端得到的请求结果:
成功得到node后端返回的结果,这表明成功实现前端代理实现跨域请求。
四、后端设置请求头实现跨域请求
接口设置请求头
// 返回json数据的get请求
app.get('/api/json', (req, res) => {// res.setHeader('Access-Control-Allow-Origin', '*') 任何请求都能跨域 不安全res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500') // 指定某个请求能跨域res.json({name: 'small5'})
})
五、Nginx代理实现跨域请求
由于本人对于Ubuntu不太了解,因此这里主要讲解一下使用Ubuntu安装nginx并实现跨域请求
5.1 安装Nginx软件
安装完成后在nginx,conf
配置代理
5.2 使用Ubuntu安装nginx
在Microsoft Store中安装对应的Ubuntu,我安装的是以下版本。
下载完成后启动Ubuntu,可能会报错解决方式参考:Ubuntu 20.04.4 LTS 报错解决方案。
Ubuntu正常启动后输入apt-get install nginx
安装nginx,如果报没有权限的错误,解决这个问题,需要以root用户身份或具有sudo权限的用户身份运行命令。可以尝试在命令前加sudo
。
安装完成后再次输入命令,验证安装结果,得到如下结果表示安装成功
接着我们打开资源管理器,找到Linux目录,安装的nginx默认是在ect文件夹下,
nginx的默认配置文件是在sites-avaliable文件夹下
下面我们打开默认配置文件找到默认服务配置的server配置一个代理。
注意,使用nginx配置代理不能使用localhost,必须使用Windows主机的ip,打开Ubuntu输入cat /etc/resolv.conf
可以获取到主机ip。
我们可以验证一下使用Windows主机ip能否请求成功接口。
下面我们配置好后端node接口并启动服务器如下图:
在Ubuntu上使用命令curl http://主机IP:服务器端口号/接口地址
发送请求。
想了解curl命令可以查看博客:技术分享 | 使用 cURL 发送请求
可以看到返回正确结果,接口发送成功,这表明使用Windows主机ip作为代理域名是没有问题的。
验证Windows主机ip地址作为代理域名没有问题后,我们再使用Windows主机ip在nginx配置文件中配置代理如下:
这里我遇到一个问题,不管是使用记事本还是vscode打开配置文件,再修改编辑后保存会无法保存,尝试了好几次都保存不了,后面我是通过在Ubuntu的Linux系统中使用vim编辑器打开配置文件,然后修改保存,这其中又遇到一个问题,如果没有加sudo权限的话执行vim 配置文件路径
打开后修改文件保存会报此文件是只读文件,不允许修改,因此要在指令前加sudo,提供sudo权限后选择输入E,进入编辑,修改后保存可以看到配置文件成功被修改了。
关于vim编辑器的基本使用可以查看我的博客git的基本使用中的预备知识那节内容。
接着我们在Ubuntu中输入nginx启动nginx,我这里没有权限,添加了sudo后才启动成功,另外由于配置文件的location拼写错误还报错了一次。如下:
接着在浏览器地址栏输入localhost:80
回车,得到如下页面表示nginx启动成功
下面就不再nginx写代码了,直接在开发者工具内发送请求验证是否实现跨域请求是一样的。
通过查看请求状态码可以验证成功实现了跨域请求
使用nginx代理实现跨域适合项目上线时使用,因此这种方式使用非常普遍。
以上就是使用nginx代理实现跨域请求的全部内容了。
相关文章:

跨域+四种解决方法
文章目录 一、跨域二、JSONP实现跨域请求三、前端代理实现跨域请求四、后端设置请求头实现跨域请求五、Nginx代理实现跨域请求5.1 安装Nginx软件5.2 使用Ubuntu安装nginx 本文是在学习课程满神yyds后记录的笔记,强烈推荐读者去看此课程。 一、跨域 出于浏览器的同…...
RW-Everything的RwDrv.sys驱动调用
RW-Everything的RwDrv.sys驱动调用 一、RwDrv.sys二、示例代码三、总结 一、RwDrv.sys RW-Everything是一个硬件底层的工具,可用于物理内存、BIOS、PCI和IO端口的查看和修改,其基于驱动RwDrv.sys来实现,利用这个驱动可以实现系统的侵入。 二…...

0101docker mysql8镜像主从复制-运维-mysql
1 概述 主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从库服务器,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。 Mysql支持一台主库同时向多台从库进行复制,从库同时可以…...

uC-OS2 V2.93 STM32L476 移植:系统启动篇
前言 前两篇已经 通过 STM32CubeMX 搭建了 NUCLEO-L476RG 的 STM32L476RG 的 裸机工程,下载了 uC-OS2 V2.93 的源码,并把 uC-OS2 的源文件加入 Keil MDK5 工程 本篇适配 uC-OS2 的 系统定时器(Systick)与 PendSV_Handler…...

redis 集群 1:李代桃僵 —— Sentinel
目前我们讲的 Redis 还只是主从方案,最终一致性。读者们可思考过,如果主节点凌晨 3 点突发宕机怎么办?就坐等运维从床上爬起来,然后手工进行从主切换,再通知所有的程序把地址统统改一遍重新上线么?毫无疑问…...
重置 Macbook 中MySQL 的 root 用户密码
Mac上好久前安装测试用的MySQL的Root密码忘记,猜了些常用密码都不对,只能重置密码。 重置密码 1、关闭MySQL服务,可以直接在系统偏好里关闭 sudo /usr/local/mysql/support-files/mysql.server stop 2、进入安装目录,启动安全…...
2308C++搞笑的概念化
前一篇的概念化,太搞笑 元<类 T>概念 可画要求(T&t,整 i){t.画(i);}; 构 方形{空 画(整 i){打印(2*i);} };元<可画 T>空 f(T&t,整 i){t.画(i);t.画(i); }空 主(){方形 e;f(e,33); }用得着那么复杂吗?...
修改node_modules里的源码
最近在工作中使用到一款生成二维码的依赖(以vue项目为例讲解):vue-qr,安装的4.0.9版本的,在启动工程的时候报错: You may need an appropriate loader to handle this file type后我查阅各种资料发现 1&a…...
【每日一题Day287】LC24 两两交换链表中的节点 | 模拟 递归
两两交换链表中的节点【LC24】 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 周赛暂停一周啦 思路:模拟 记录前驱…...
Java ~ Collection/Executor ~ PriorityBlockingQueue【源码】
前言 相关系列 《Java ~ Collection【目录】》(持续更新)《Java ~ Executor【目录】》(持续更新)《Java ~ Collection/Executor ~ PriorityBlockingQueue【源码】》(学习过程/多有漏误/仅作参考/不再更新)…...
Java后台生成微信小程序码并以流的形式返回给前端
后端代码 获取access_token import net.sf.json.JSONObject;public class WeChatUtil {/*** 获取token*/private static String ACCESSTOKENURL "https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appid{appId}&secret{appSecret}"…...

AtcoderABC226场
A - Round decimalsA - Round decimals 题目大意 给定一个实数X,它最多可以使用三位小数表示,而且X的小数点后有三位小数。将X四舍五入到最接近的整数并打印结果。 思路分析 可以使用round函数进行四舍五入 知识点 round(x) 是一个用来对数字进行四…...

Linux知识点 -- VS Code远程连接服务器协助开发
Linux知识点 – VS Code远程连接服务器协助开发 文章目录 Linux知识点 -- VS Code远程连接服务器协助开发一、VS Code的使用1.使用VS Code进行C语言编译与运行2.使用VS Code进行C代码的编译与运行 二、使用VS Code连接云服务器三、使用VS Code进行GDB调试 一、VS Code的使用 1…...

blender基础认识(选项开关、工具栏、视图等)
文章目录 引言一、大纲选项开关和保存启动文件1. 大纲选项1. 禁用选中2. 视图影藏3. 视图禁用4. 渲染禁用 2. 保存启动文件 二、工具栏和侧边栏1. 左侧工具栏2. 右侧工具栏 三、视图1. 视角2. 缩放3. 拖拽4. 摄像机视角5. 切换正交视图6. 局部视图7. 显示隐藏 四、添加删除物体…...
React Hooks 中的属性详解
React Hooks 是 React 16.8 版本中新增的特性,允许我们在不编写 class 的情况下使用 state 和其他的 React 特性。Hooks 是一种可以让你在函数组件中“钩入” React 特性的函数。以下是一些常用的 React Hooks,并附有详细的用法和代码示例。 1. useStat…...
工作遇到问题与解决办法(一)
一、构建父子工程 父 <groupId>com.ruoyi</groupId> <artifactId>ruoyi</artifactId> <version>3.8.5</version> <modules><module>ruoyi-admin</module><module>ruoyi-framework</module><module>…...

综合与新综合与新型交通发展趋势[75页PPT]
导读:原文《综合与新综合与新型交通发展趋势[75页PPT]》(获取来源见文尾),本文精选其中精华及架构部分,逻辑清晰、内容完整,为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式: 如需…...

【树形DP+换根思想】2022牛客多校加赛 H
登录—专业IT笔试面试备考平台_牛客网 题意: 思路: 这个虽然是树形DP,却用了换根的思想.... 首先,后缀0的个数可以转化成min(cnt2,cnt5),其中cnt2为2的因子个数,cnt5为5的因子个数 然后进行DP 设dp[u]…...

Gitlab CI/CD笔记-第二天-GitOps的流水线常用关键词(1)
一、常用关键词 在Gitlab项目的根目录需要创建一个 .gitlab-ci.yaml的文件。 这个文件就是定义的流水线。Call :"Pipeline as code" 二、这条流水线怎么写? 一、掌握常用的关键词即可。 1.关键词分类 1.全局关键词 Global Keywards 2.任务关键词…...

Spring Boot3.0(一):入门篇
什么是 Spring Boot Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。 用我的话来理解,就是 Spring…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...