大白话跨域问题的原理与多种解决方法的实现

大白话跨域问题的原理与多种解决方法的实现

跨域问题原理

简单来说,当一个网页中的JavaScript代码想要去访问另一个不同域名、端口或协议的服务器上的数据时,就会出现跨域问题。这是浏览器的一种安全机制,为了防止恶意网站窃取用户信息等。比如,你在自己家网站(www.example.com)上写的代码,想去访问别人家网站(www.other.com)的数据,浏览器就会觉得有风险,可能会阻止这个访问,这就是跨域问题。

解决方法及代码示例

  1. JSONP(JSON with Padding)
    • 原理:利用<script>标签没有跨域限制的特点,通过动态创建<script>标签来请求数据,服务器返回的是一段JavaScript代码,把数据放在一个函数调用里。
    • 代码示例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JSONP Example</title>
</head><body><script>// 定义一个函数,用来处理服务器返回的数据function handleData(data) {console.log('Received data:', data);}// 创建一个script标签var script = document.createElement('script');// 设置script标签的src属性,指向服务器接口,并且带上回调函数名script.src = 'http://example.com/api/data?callback=handleData';// 将script标签添加到页面中document.head.appendChild(script);</script>
</body></html>
- **注释**:上述代码中,先定义了`handleData`函数用于处理服务器返回的数据。然后创建`<script>`标签,设置其`src`属性为服务器接口地址,并通过`callback`参数指定回调函数名。最后将`<script>`标签添加到页面,浏览器会自动加载该脚本,服务器返回的脚本会执行`handleData`函数并传入数据。
  1. CORS(Cross-Origin Resource Sharing)
    • 原理:服务器通过设置响应头,告诉浏览器哪些域名可以访问它的资源,浏览器根据这些响应头来决定是否允许跨域请求。
    • 代码示例(以Express为例)
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');next();
});app.get('/api/data', (req, res) => {const data = { message: 'Hello from server' };res.json(data);
});const port = 3000;
app.listen(port, () => {console.log(`Server running on port ${port}`);
});
- **注释**:首先引入`express`模块创建服务器。通过`app.use`中间件设置`Access-Control-Allow-Origin`响应头为`*`,表示允许所有域名访问,还设置了允许的请求方法和请求头。当访问`/api/data`接口时,服务器返回一个包含消息的JSON数据。
  1. 代理服务器
    • 原理:在本地搭建一个代理服务器,浏览器先向代理服务器发送请求,代理服务器再向目标服务器请求数据,然后把数据返回给浏览器,这样就不存在跨域问题了,因为浏览器和代理服务器在同一个域。
    • 代码示例(以webpack-dev-server代理为例)
// webpack.config.js
module.exports = {// 其他配置项...devServer: {proxy: {'/api': {target: 'http://example.com',changeOrigin: true}}}
};
- **注释**:在`webpack`配置文件中,通过`devServer.proxy`设置代理。当请求以`/api`开头时,`webpack-dev-server`会将请求转发到`http://example.com`,`changeOrigin`设置为`true`表示修改请求头中的`Origin`字段,使其与目标服务器的域名一致。
  1. postMessage
    • 原理:用于窗口之间的通信,比如一个页面中的iframe和父页面之间。可以通过postMessage方法发送消息,在接收方通过message事件监听接收消息。
    • 代码示例
<!-- 父页面 -->
<!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><iframe id="myFrame" src="http://example.com/child.html"></iframe><script>// 监听来自子窗口的消息window.addEventListener('message', function (event) {console.log('Received message from child:', event.data);});// 向子窗口发送消息const frame = document.getElementById('myFrame');frame.contentWindow.postMessage('Hello from parent', 'http://example.com');</script>
</body></html><!-- 子页面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><script>// 监听来自父窗口的消息window.addEventListener('message', function (event) {console.log('Received message from parent:', event.data);// 向父窗口回复消息event.source.postMessage('Hello from child', event.origin);});</script>
</body></html>

跨域问题常见的错误提示有哪些?
跨域问题出现时,浏览器或服务器通常会给出一些错误提示,以下是一些常见的错误提示及通俗解释:

  • Access to XMLHttpRequest at ‘xxx’ from origin ‘xxx’ has been blocked by CORS policy
    • 解释:这句话的意思是,你的JavaScript代码通过XMLHttpRequest(一种常用的网络请求方式)去请求一个网址(‘xxx’)的数据,但是浏览器发现这个请求的来源网址(也就是你当前网页所在的网址’xxx’)和要请求的网址不一样,而且服务器那边没有设置允许你这个来源网址来请求数据,所以就按照跨域的规则把你的请求给拦住了,不允许访问。
  • No ‘Access-Control-Allow-Origin’ header is present on the requested resource
    • 解释:浏览器在请求数据时,发现服务器返回的信息里面没有Access-Control-Allow-Origin这个响应头。这个响应头本来是用来告诉浏览器,哪些网址可以访问这个服务器上的资源。现在没有这个头,浏览器就不知道让不让访问,所以就认为是跨域问题,阻止了请求。
  • Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at xxx
    • 解释:浏览器有一个“同源策略”,就是说一个网页里的代码通常只能访问和它在同一个域名、端口和协议下的资源。这里就是说你要访问的那个远程资源(‘xxx’)和当前网页不是同一个来源,违反了“同源策略”,所以浏览器把你的请求给拦住了,不让你读取那个远程资源的数据。
  • Failed to load xxx: No ‘Access-Control-Allow-Methods’ header is present on the requested resource
    • 解释:和前面没有Access-Control-Allow-Origin头类似,这里是服务器返回的信息里没有Access-Control-Allow-Methods这个头。这个头是用来告诉浏览器,允许使用哪些HTTP方法(比如GET、POST等)来请求资源。没有这个头,浏览器就不知道能不能用你代码里的那种方法去请求,所以就报错说加载资源失败了,也是因为跨域问题导致的。
  • Request header field xxx is not allowed by Access-Control-Allow-Headers in preflight response
    • 解释:在正式发送请求之前,浏览器可能会先发送一个“预检”请求,看看服务器支不支持你要发送的请求。这里说的是你请求头里面有个字段(‘xxx’),服务器在“预检”响应的Access-Control-Allow-Headers里没有允许这个字段。也就是说,服务器不允许你用这个字段来请求数据,所以就报错了,这也是跨域相关的一个错误提示。

除了JSONP,还有哪些方法可以解决跨域问题?

除了JSONP之外,解决跨域问题还有以下几种常见方法:

CORS(跨域资源共享)

  • 原理:就是服务器设置一些响应头,告诉浏览器哪些域名的网页可以访问它的资源,以及允许使用哪些HTTP方法、请求头字段等。浏览器根据这些信息来判断这个跨域请求是否合法。
  • 实现步骤
    • 服务端配置:在服务器端设置Access-Control-Allow-Origin响应头,指定允许访问的源。比如,如果要允许http://example.com这个域名访问,就设置Access-Control-Allow-Origin: http://example.com。如果想允许所有域名访问,就设置为*。还可以设置Access-Control-Allow-Methods来指定允许的HTTP方法,如GETPOST等;设置Access-Control-Allow-Headers来指定允许的请求头字段。
    • 客户端请求:客户端正常发送跨域请求就行,不用做特殊处理,浏览器会根据服务器返回的响应头来判断是否允许访问。
  • 代码示例(以Node.js为例)
const express = require('express');
const app = express();// 设置允许跨域访问该服务的域名
app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', 'http://example.com');res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');res.setHeader('Access-Control-Allow-Headers', 'Content-Type');next();
});// 处理请求的路由
app.get('/data', (req, res) => {// 返回数据res.json({ message: '这是来自服务器的数据' });
});const port = 3000;
app.listen(port, () => {console.log(`服务器在端口 ${port} 上运行`);
});

代理服务器

  • 原理:把跨域请求先发给自己服务器上的一个代理接口,然后由这个代理接口再去请求目标服务器的数据,最后把数据返回给客户端。因为代理接口和客户端代码在同一个域名下,所以就不存在跨域问题了。
  • 实现步骤
    • 搭建代理服务器:在自己的服务器上设置一个代理服务,它可以接收客户端的请求,然后转发到目标服务器。
    • 配置代理规则:告诉代理服务器哪些请求需要转发,以及转发到哪里。比如,把客户端对/api/*路径的请求转发到http://targetserver.com/api/*
    • 客户端请求:客户端把原本要发给目标服务器的请求,改成发给代理服务器的接口。
  • 代码示例(以使用http-proxy-middleware为例)
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();// 创建代理中间件
const proxy = createProxyMiddleware('/api', {target: 'http://targetserver.com', // 目标服务器地址changeOrigin: true
});// 使用代理中间件
app.use(proxy);const port = 3000;
app.listen(port, () => {console.log(`服务器在端口 ${port} 上运行`);
});

WebSocket

  • 原理:WebSocket是一种在单个TCP连接上进行全双工通信的协议,它不受同源策略的限制,可以在不同源的客户端和服务器之间进行通信。
  • 实现步骤
    • 服务端实现:在服务器端使用WebSocket库来创建WebSocket服务器,监听客户端的连接请求,接收和处理客户端发送的消息,向客户端发送消息。
    • 客户端实现:在客户端使用WebSocket API来连接服务器,发送和接收消息。
  • 代码示例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>WebSocket示例</title>
</head><body><script>// 创建WebSocket连接const socket = new WebSocket('ws://example.com:8080');// 连接成功后的回调socket.onopen = function () {console.log('连接成功');// 发送消息socket.send('这是客户端发送的消息');};// 接收消息的回调socket.onmessage = function (event) {console.log('收到服务器消息:', event.data);};// 连接关闭的回调socket.onclose = function () {console.log('连接关闭');};</script>
</body></html>
const WebSocket = require('ws');// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function (ws) {console.log('有客户端连接');// 接收客户端消息ws.on('message', function (message) {console.log('收到客户端消息:', message);// 向客户端发送消息ws.send('这是服务器回复的消息');});// 客户端关闭连接的处理ws.on('close', function () {console.log('客户端连接关闭');});
});

postMessage

  • 原理:HTML5的postMessage API允许在不同源的窗口之间进行安全的跨域通信。比如在一个网页中嵌入了另一个不同源的iframe,就可以通过postMessage来实现它们之间的通信。
  • 实现步骤
    • 发送消息:在发送消息的窗口中,使用postMessage方法发送消息,指定要发送的数据和目标窗口的源。
    • 接收消息:在接收消息的窗口中,监听message事件,在事件回调中处理接收到的消息。
  • 代码示例
<!-- 主页面 -->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>主页面</title>
</head><body><iframe id="myFrame" src="http://example.com/iframe.html"></iframe><script>const iframe = document.getElementById('myFrame');// 向iframe发送消息iframe.contentWindow.postMessage('这是主页面发送的消息', 'http://example.com');// 接收来自iframe的消息window.addEventListener('message', function (event) {if (event.origin === 'http://example.com') {console.log('收到iframe的消息:', event.data);}});</script>
</body></html>
<!-- iframe页面 -->
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>iframe页面</title>
</head><body><script>// 接收来自主页面的消息window.addEventListener('message', function (event) {if (event.origin === 'http://main.com') {console.log('收到主页面的消息:', event.data);// 向主页面发送回复消息window.parent.postMessage('这是iframe页面的回复', 'http://main.com');}});</script>
</body></html>

如何在前后端分离的项目中处理跨域问题?
在前后端分离的项目里,处理跨域问题主要有在前端处理和在后端处理两种思路,以下是一些常见的方法及具体做法:

前端处理

  • 使用代理服务器
    • 原理:利用开发服务器提供的代理功能,将前端对后端接口的请求转发到真实的后端服务器地址,让浏览器以为所有请求都在同一个域内,从而避开浏览器的跨域限制。
    • 操作:以Vue项目为例,在vue.config.js文件中可以进行如下配置:
module.exports = {devServer: {proxy: {'/api': {target: 'http://backendserver.com', // 后端服务器地址changeOrigin: true,pathRewrite: {'^/api': '' // 重写路径,去除/api前缀}}}}
};
- **效果**:这样配置后,前端代码中所有以`/api`开头的请求都会被代理到`http://backendserver.com`,就像请求本地资源一样,解决了跨域问题。

后端处理

  • CORS(跨域资源共享)
    • 原理:服务器通过设置特定的响应头,告诉浏览器哪些域名的前端页面可以访问它的资源,以及允许使用哪些HTTP方法、请求头字段等,让浏览器能够判断这个跨域请求是否合法。
    • 操作:以使用Express框架的Node.js后端为例,可以这样设置:
const express = require('express');
const app = express();// 设置允许跨域访问该服务的域名
app.use((req, res, next) => {res.setHeader('Access-Control-Allow-Origin', 'http://frontend.com'); // 替换为前端域名res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');res.setHeader('Access-Control-Allow-Headers', 'Content-Type');next();
});// 处理请求的路由
app.get('/data', (req, res) => {// 返回数据res.json({ message: '这是来自服务器的数据' });
});const port = 3000;
app.listen(port, () => {console.log(`服务器在端口 ${port} 上运行`);
});
- **效果**:上述代码设置了允许`http://frontend.com`这个域名的前端页面访问后端的`/data`接口,并且允许使用`GET`、`POST`、`PUT`、`DELETE`这些HTTP方法,请求头中可以包含`Content-Type`字段。
  • JSONP
    • 原理:利用<script>标签不受同源策略限制的特点,通过动态创建<script>标签来请求跨域数据,服务器返回的是一段JavaScript代码,通常是一个函数调用,把数据作为参数传递给这个函数,前端通过定义这个函数来处理接收到的数据。
    • 操作:后端代码示例(以Express为例):
const express = require('express');
const app = express();app.get('/data.jsonp', (req, res) => {const callback = req.query.callback;const data = { message: '这是来自服务器的JSONP数据' };// 将数据包装成函数调用的形式返回res.send(`${callback}(${JSON.stringify(data)})`);
});const port = 3000;
app.listen(port, () => {console.log(`服务器在端口 ${port} 上运行`);
});
- **效果**:前端页面可以通过以下方式请求数据:
<!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>function handleData(data) {console.log(data.message);}// 动态创建script标签const script = document.createElement('script');script.src = 'http://backendserver.com/data.jsonp?callback=handleData';document.head.appendChild(script);</script>
</body></html>

上述代码中,前端通过动态创建<script>标签,请求后端的/data.jsonp接口,并指定callback参数为handleData,后端将数据包装成handleData({ message: '这是来自服务器的JSONP数据' })的形式返回,前端的handleData函数就可以接收到并处理数据。不过要注意,JSONP只支持GET请求。

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

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

相关文章

【网络编程】之TCP实现客户端远程控制服务器端及断线重连

【网络编程】之TCP实现客户端远程控制服务器端及断线重连 TCP网络通信实现客户端简单远程控制主机基本功能演示通信过程代码实现服务器模块执行命令模块popen系列函数 客户端模块服务器主程序 windows作为客户端与服务器通信#pragma comment介绍 客户端使用状态机断线重连代码实…

Git快速入门

文章目录 Git简介准备工作常用的Linux命令git配置 git工作原理git项目创建和克隆git基本操作命令git忽略文件配置ssh远程连接 IDEA集成Gitgit分支&#xff08;多人开发&#xff09;公司中用到的&#xff08;很清楚&#xff09; Git 简介 Git就是版本控制的工具 下面这个叫手动…

Redis 的几个热点知识

前言 Redis 是一款内存级的数据库&#xff0c;凭借其卓越的性能&#xff0c;几乎成为每位开发者的标配工具。 虽然 Redis 包含大量需要掌握的知识&#xff0c;但其中的热点知识并不多。今天&#xff0c;『知行』就和大家分享一些 Redis 中的热点知识。 Redis 数据结构 Redis…

深入解析Java虚拟机(JVM)的核心组成

深入解析Java虚拟机&#xff08;JVM&#xff09;的核心组成 Java虚拟机&#xff08;JVM&#xff09;作为Java语言跨平台的核心实现&#xff0c;其架构设计精妙而复杂。理解JVM的组成部分&#xff0c;是掌握Java内存管理、性能调优和问题排查的关键。本文将从四大核心模块剖析J…

GIT工具学习【2】:分支

1.什么是分支 新建一个分支&#xff0c;可以认为把当前项目copy了一份&#xff0c;不太严谨&#xff0c;没毛病&#xff0c;里面虽然文件内容和名字相同&#xff0c;其实互相没有关系。 2.什么是合并分支 就是把两个分支&#xff08;项目文件夹&#xff09;合并在一起 git m…

40岁开始学Java:Java中单例模式(Singleton Pattern),适用场景有哪些?

在Java中&#xff0c;单例模式&#xff08;Singleton Pattern&#xff09;用于确保一个类只有一个实例&#xff0c;并提供全局访问点。以下是详细的实现方式、适用场景及注意事项&#xff1a; 一、单例模式的实现方式 1. 饿汉式&#xff08;Eager Initialization&#xff09; …

Linux常见基本指令(一)

目录 前言 1、ls指令 2、用户相关指令 3、pwd指令 4、cd指令 相对路径与绝对路径 5、创建、删除文件和目录相关的指令 创建相关的指令 删除相关的指令 6、拷贝、移动和重命名 cp指令 mv指令 前言 学习Linux的过程中一定要多自己动手&#xff0c;Linux的指令繁多&a…

测试金蝶云的OpenAPI

如何使用Postman测试K3Cloud的OpenAPI 1. 引言 在本篇博客中&#xff0c;我将带你逐步了解如何使用Postman测试和使用K3Cloud的OpenAPI。内容包括下载所需的SDK文件、配置文件、API调用及测试等步骤。让我们开始吧&#xff01; 2. 下载所需的SDK文件 2.1 获取SDK 首先&…

Tomcat

1.Tomcat是什么&#xff1f; Tomcat 是一个开源的、轻量级的 Servlet 容器&#xff0c;也被称为 Web 服务器&#xff0c;由 Apache 软件基金会的 Jakarta 项目开发&#xff0c;在 Java Web 开发领域应用广泛。 1&#xff09;Servlet 容器&#xff1a;Servlet 是 Java 语言编写…

【windows driver】 开发环境简明安装教程

一、下载路径 https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads 二、安装步骤&#xff1a; 1、安装Visual Studio IDE 笔者建议安装最新版本&#xff0c;可以向下兼容。发文截止到目前&#xff0c;VS2022是首选&#xff0c;当前笔者由于项…

长时间目标跟踪算法(3)-GlobalTrack:A Simple and Strong Baseline for Long-termTracking

GlobalTrack的原始论文和源码均已开源&#xff0c;下载地址。 目录 背景与概述 1.1 长期视觉跟踪的挑战 1.2 现有方法的局限性 1.3 GlobalTrack的核心思想 算法原理与架构 2.1 全局实例搜索框架 2.2 Query-Guided RPN&#xff08;QG-RPN&#xff09; 2.3 Query-Guided RCNN&a…

使用mermaid查看cursor程序生成的流程图

一、得到cursor生成的流程图文本 cursor写的程序正常运行后&#xff0c;在对话框输入框中输入诸如“请生成扫雷的代码流程图”&#xff0c;然后cursor就把流程图给生成了&#xff0c;但是看到的还是文本的样子&#xff0c;保留这部分内容待用 二、注册一个Mermaid绘图账号 …

MacOS本地部署Deepseek,不联网也可以使用AI,保护隐私

苹果笔记本本地部署deepseek主要用到Ollama与open-webui 1. 安装Ollama “Ollama” 是一个轻量级的 AI 模型运行时环境&#xff08;runtime&#xff09;&#xff0c;旨在简化在本地部署和使用大语言模型&#xff08;LLM&#xff09;的过程。它由 Vicarious 公司开发&#xff…

unity学习62,尝试做第一个小游戏项目:flappy bird

目录 学习参考 1 创建1个unity 2D项目 1.1 2D项目模板选择 1.1.1 2D(built-in-Render pipeline) 1.1.2 universe 2D 1.1.3 这次选择 2D(built-in-Render pipeline) 1.2 创建项目 1.2.1 注意点 1.2.2 如果想修改项目名 2 导入美术资源包 2.1 下载一个flappy bird的…

基于Matlab的多目标粒子群优化

在复杂系统的设计、决策与优化问题中&#xff0c;常常需要同时兼顾多个相互冲突的目标&#xff0c;多目标粒子群优化&#xff08;MOPSO&#xff09;算法应运而生&#xff0c;作为群体智能优化算法家族中的重要成员&#xff0c;它为解决此类棘手难题提供了高效且富有创新性的解决…

使用DiskGenius工具来实现物理机多硬盘虚拟化迁移

使用DiskGenius工具来实现物理机多硬盘虚拟化迁移 概述准备工作注意事项实操过程记录1、Win7虚拟机&#xff0c;安装有两个硬盘&#xff08;硬盘0和硬盘1&#xff09;&#xff0c;各分了一个区&#xff0c;磁盘2是一块未使用的磁盘2、运行DiskGenius程序&#xff0c;记录现有各…

win本地vscode通过代理远程链接linux服务器

时间&#xff1a;2025.2.28 1. win本地下载nmap.exe nmap官网 https://nmap.org/或者 https://nmap.org/download#windows下载win版本并安装。 2. vscode插件Remote-SSH 插件下载Remote-SSH 3. 配置 按照图中顺序配置ssh 1.点击左侧工具栏的“小电视”图标 2.点击ssh的…

yolo初体验

看别人说的好简单,3行代码完成yolo11: from ultralytics import YOLO model YOLO("yolo11x.pt")##第一次运行自动下载 model.predict(source"0",showTrue) 当然代码没错:但是环境不好配: 首先:pip install ultralytics 会主动下载依赖 pytorch pandas-…

TCP 连接故障排查与 SYN 洪泛攻击防御

1 SYN 洪泛攻击防御 1.1 SYN Flood是什么&#xff1f; SYN Flood是互联网上最原始、最经典的DDoS&#xff08;Distributed Denial of Service&#xff0c;分布式拒绝服务&#xff09;攻击之一&#xff0c;旨在耗尽可用服务器资源&#xff0c;致使服务器无法传输合法流量。 SYN…

ArcGIS Pro应用指南:如何为栅格图精确添加坐标信息

一、引言 在地理信息系统中&#xff0c;栅格图是一种重要的数据类型。 然而&#xff0c;有时我们从网络上获取的栅格图并不包含坐标信息&#xff0c;这使得它们难以与其他带有坐标信息的数据进行集成和分析。 为了解决这一问题&#xff0c;我们需要对栅格图进行地理配准&…