深入解析:前端跨域问题及其CORS、代理、JSONP、Nginx反向代理等解决方案

在这里插入图片描述

前端跨域是指在浏览器环境下,当一个网页(源)尝试访问与自身源不同的服务器资源(目标源)时,由于浏览器的同源策略限制而产生的访问限制现象。同源策略(Same-Origin Policy)是浏览器实施的一种安全机制,用于防止恶意网站通过脚本对其他网站的数据进行非法访问,以保护用户的隐私和安全。

按照同源策略的规定,只有当请求的源(即协议、域名、端口号三者完全相同)与目标源相匹配时,浏览器才会允许脚本(如JavaScript)发起的网络请求(如Ajax、Fetch、XMLHttpRequest)成功访问目标源的资源。否则,这些请求会被浏览器视为跨域请求,并可能被拦截或阻止。

具体来说,以下情况会被浏览器判定为跨域:

  • 协议不同:如一个HTTPS页面尝试访问HTTP资源。
  • 域名不同:如www.example.com的页面尝试访问api.example.org的API。
  • 端口号不同:如localhost:3000的页面尝试访问localhost:8080的服务。

跨域问题主要影响浏览器端的JavaScript在以下场景中的行为:

  1. AJAX请求:JavaScript通过XMLHttpRequest或Fetch API发起的异步数据请求。
  2. WebSockets连接:JavaScript创建的WebSocket连接,用于建立浏览器与服务器间的双向通信。
  3. 嵌入资源:如尝试在页面中通过<img>, <script>, <link>, <iframe>等标签加载跨域的图片、脚本、样式表或嵌入式页面。
  4. 跨窗口交互:如尝试通过window.postMessage()方法与不同源的窗口进行通信。

虽然同源策略对大部分跨域请求进行了限制,但对某些特定类型的资源(如上述的嵌入资源)和某些特定操作(如跨窗口通信)放宽了限制。此外,现代Web开发中也发展出了一系列技术与策略来解决或绕过跨域限制,包括但不限于:

  • CORS(Cross-Origin Resource Sharing,跨源资源共享):服务器通过返回特定的HTTP响应头,允许浏览器跨域访问其资源。
  • 代理:通过在本地或服务器端设置代理,将跨域请求转发至目标服务器,使得浏览器认为请求在同一源内。
  • JSONP(JSON with Padding):利用 <script> 标签不受同源策略限制的特性,通过动态插入脚本标签加载跨域数据。
  • iframe与postMessage:在同源的iframe中加载跨域资源,然后通过window.postMessage()进行跨窗口通信。
  • Nginx反向代理:在生产环境中,使用Nginx等Web服务器作为反向代理,转发客户端的跨域请求,并在响应时添加CORS头。

前端开发者在遇到跨域问题时,需要根据项目需求、开发环境和服务器配置选择适用的跨域解决方案,以确保浏览器端能够顺利访问所需跨域资源。

以下是6种常见的前端跨域解决方案的详解与举例:

1. CORS(Cross-Origin Resource Sharing,跨源资源共享)

原理:CORS是一种W3C标准,通过服务器返回特定的HTTP响应头,允许浏览器与服务器之间进行跨源通信。服务器明确声明哪些源可以访问其资源,以及允许的请求方法、头部和预检要求。

举例:服务器端(如Node.js Express应用)设置CORS响应头:

const express = require('express');
const app = express();app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有源或指定源res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); // 允许的方法res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); // 允许的头部if (req.method === 'OPTIONS') {res.sendStatus(204); // 对预检请求(OPTIONS)返回空响应体} else {next(); // 其他请求继续处理}
});app.get('/data', (req, res) => {res.json({ message: 'Hello, CORS!' });
});app.listen(3000, () => {console.log('CORS-enabled server listening on port 3000');
});

前端(如使用Fetch API)发起跨域请求:

fetch('http://example.com:3000/data').then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));

2. 代理(Proxy)

原理:通过本地开发服务器(如Webpack Dev Server、Vue CLI Serve)的代理功能,将前端发出的跨域请求转发到目标服务器。浏览器认为请求始终在同一源内,避免了同源策略限制。

举例:在Vue CLI创建的项目中,vue.config.js配置代理:

module.exports = {devServer: {proxy: {'/api': {target: 'http://example.com:8080', // 目标服务器地址changeOrigin: true, // 是否更改请求头中的HostpathRewrite: { '^/api': '' }, // 路径重写},},},
};

前端发起请求:

axios.get('/api/data').then(response => console.log(response.data)).catch(error => console.error('Error:', error));

3. JSONP(JSON with Padding)

原理:利用 <script> 标签不受同源策略限制的特性,动态插入带有跨域URL的<script>标签。服务端返回一个调用前端预定义回调函数的JS代码片段,将数据作为参数传递。

举例:前端定义回调函数:

function handleJsonpData(data) {console.log('Received JSONP data:', data);
}const script = document.createElement('script');
script.src = 'http://example.com/jsonp?callback=handleJsonpData';
document.head.appendChild(script);

服务端响应JSONP请求(假设使用Node.js):

const http = require('http');http.createServer((req, res) => {const callbackName = req.query.callback;const data = { message: 'Hello, JSONP!' };res.setHeader('Content-Type', 'application/javascript');res.end(`${callbackName}(${JSON.stringify(data)});`);
}).listen(8080, () => {console.log('JSONP server listening on port 8080');
});

4. Nginx反向代理

原理:在生产环境中,使用Nginx等Web服务器作为反向代理,将客户端的跨域请求转发到目标服务器,并在响应时添加CORS头。客户端感知不到实际服务器源,从而规避跨域限制。

举例:Nginx配置文件中的反向代理配置:

server {listen 80;location /api {proxy_pass http://backend.example.com:8080; // 目标服务器地址proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;add_header 'Access-Control-Allow-Origin' '*' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;}
}

前端请求保持不变,访问代理服务器地址:

fetch('/api/data').then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));

5. iframe与postMessage

原理:将跨域请求封装在同源的iframe中,通过window.postMessage方法实现跨窗口通信,使主窗口能够获取到iframe内加载的跨域资源数据。

举例:主页面创建iframe并监听message事件:

<iframe id="cross-origin-frame" src="http://example.com/cross-origin.html"></iframe><script>window.addEventListener('message', function(event) {if (event.origin !== 'http://example.com') return; // 验证来源console.log('Received data from iframe:', event.data);});// 如果需要与iframe通信,可以向其发送消息document.getElementById('cross-origin-frame').contentWindow.postMessage({ action: 'getData' }, 'http://example.com');
</script>

iframe页面接收消息并响应:

<script>window.addEventListener('message', function(event) {if (event.origin !== 'http://localhost:3000') return; // 验证来源if (event.data.action === 'getData') {fetch('/api/data').then(response => response.json()).then(data => {event.source.postMessage(data, event.origin); // 将数据回传给主页面}).catch(error => console.error('Error:', error));}});
</script>

6. WebSocket

原理:WebSocket协议支持浏览器与服务器之间建立全双工的持久连接,一旦连接建立,客户端与服务器端就可以自由地互相发送数据,不受同源策略限制。

举例:前端创建WebSocket连接:

const socket = new WebSocket('ws://example.com/ws');socket.addEventListener('open', function(event) {console.log('WebSocket connection established.');
});socket.addEventListener('message', function(event) {console.log('Received data from server:', event.data);
});// 发送数据到服务器
socket.send(JSON.stringify({ message: 'Hello, WebSocket!' }));

服务器端(假设使用Node.js的ws库):

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) {ws.on('message', function incoming(message) {console.log('Received data from client:', message);const data = { response: 'Hello, client!' };ws.send(JSON.stringify(data)); // 回传数据到客户端});
});

综上所述,前端跨域问题有多种解决方案,其中CORS、代理(尤其是开发阶段的代理)、JSONP、Nginx反向代理是较为常用且现代的解决手段。根据项目需求和环境,选择合适的跨域策略。对于更复杂或特定场景,可以考虑使用iframe与postMessage、WebSocket等技术。
在这里插入图片描述

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

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

相关文章

SL3037内置MOS管 耐压60V降压恒压芯片 降12V或降24V 电路简单

SL3037B是一款内置功率MOSFET的单片降压型开关模式转换器&#xff0c;具有以下特点&#xff1a; 1. 高效率&#xff1a;采用开关式降压技术&#xff0c;仅在需要调节输出电压时才会消耗能量&#xff0c;从而提高了整体的效率。 2. 稳定性好&#xff1a;通过精确的内部电路设计…

RS®FSH 手持式频谱分析仪

手持式频谱分析仪 R&SFSH -彰显移动性能r- 一体化 灵敏度出色 9 kHz 至 20 GHz 该一体化手持式分析仪非常适合现场的常规测量任务 R&SFSH 手持式频谱分析仪还可以用作网络分析仪、电缆与天线分析仪、干扰捕获分析仪和功率计。这款多功能分析仪可实现简单高效的现…

Axure RP 9 for Mac/win:打造极致交互体验的原型设计神器

在数字化浪潮席卷全球的今天&#xff0c;原型设计作为产品开发的关键环节&#xff0c;其重要性不言而喻。Axure RP 9&#xff0c;作为一款专为设计师和开发者打造的原型设计软件&#xff0c;以其出色的交互设计能力和高效的协作体验&#xff0c;赢得了广大用户的青睐。 Axure …

第一讲 - Java入门

第一讲 - Java入门 文章目录 第一讲 - Java入门1. 人机交互1.1 什么是cmd&#xff1f;1.2 如何打开CMD窗口&#xff1f;1.3 常用CMD命令1.4 CMD练习1.5 环境变量 2. Java概述1.1 Java是什么&#xff1f;1.2下载和安装1.2.1 下载1.2.2 安装1.2.3 JDK的安装目录介绍 1.3 HelloWor…

【Qt】.ui文件转.h文件

1、打开qt命令行 2、转换 uic -o ui.h mainwindow.ui

Vue页面生成导出PDF文件

第一种&#xff1a; 使用浏览器自带打印方法window.print(); 也可使用print-js插件&#xff08;原理相同&#xff09; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>printDemo</title> </…

ACL的知识点和实验

1.ACL的组成 ACL由若干条permit或deny语句组成。每条语句就是该ACL的一条规则&#xff0c;每条语句中的permit或deny就是与这条规则相对应的处理动作。 2.规则编号 &#xff08;1&#xff09;一个ACL中的每一条规则都有一个相应的编号。 &#xff08;2&#xff09;步长是系…

【电控实物-infantry】

云台电机参数 电机内部参数 相电阻:Rs1.8欧 相电感:Ls5.7810^-3H 转矩常数:Kt 0.741 NM/A 转动惯量:J KG-m^2 电机接收数据&#xff1a;-16384到16384&#xff08;-3A到3A&#xff09; 电机反馈&#xff1a;速度RPM rad/s &#xff08;2πrpm&#xff09;/60 C板陀螺仪&…

汇智知了堂走进宜宾学院,共话国产化信创未来!

在春意盎然的四月&#xff0c;汇智知了堂以其深厚的品牌底蕴和卓越的教育品质&#xff0c;再次展现了其在教育领域的领先地位。4月18日&#xff0c;汇智知了堂走进宜宾学院&#xff0c;为广大学子带来了一场关于国产化信创时代的技术变革与专业学习建议的讲座。 汇智知了堂作…

【Linux学习】Linux进程(二)

文章目录 &#x1f4d5;查看进程&#x1f680;/proc目录&#x1f680;cwd与exe &#x1f4d5;改变进程的工作目录&#x1f680;chdir指令 &#x1f4d5;vim卡住了怎么解决 本篇文章接着【LInux进程&#xff08;一&#xff09;】继续编写。 &#x1f4d5;查看进程 &#x1f68…

力扣HOT100 - 105. 从前序与中序遍历序列构造二叉树

解题思路&#xff1a; 分治 以中序遍历为参照&#xff0c;用前序遍历的节点构建二叉树。 root 1 index - left表示前序遍历右子树的开始节点&#xff0c;即当前节点的下一个节点左子树长度。 class Solution {int[] preorder;HashMap<Integer, Integer> map new Ha…

如何在Windows服务做性能测试(CPU、磁盘、内存)

目录 前言1. 基本知识2. 参数说明 前言 由于需要做一些接口测试&#xff0c;测试是否有真的优化 1. 基本知识 该基本知识主要用来用到Performance Monitor&#xff0c;以下着重介绍下这方面的知识 性能监视器&#xff08;Performance Monitor&#xff09;&#xff1a;Windo…