拓展边界:前端世界的跨域挑战

目录

什么是跨域

概念

同源策略及限制内容

常见跨域场景

如何解决跨域

CORS

Nginx代理跨域

Node中间件代理跨域

WebSocket

postMessage

JSONP

其他


什么是跨域

概念

在此之前,我们了解一下一个域名地址的组成:

跨域指的是在网络安全中,由于浏览器的同源策略(Same-Origin Policy)限制,当一个网页的协议、域名或端口与另一个网页的协议、域名或端口不同时,就存在跨域问题。如果缺少同源策略的限制,可能会导致安全隐患,如跨站脚本攻击(XSS)或跨站请求伪造(CSRF)等。

同源策略及限制内容

同源策略是浏览器的一项安全机制,它限制了来自不同源的脚本对当前文档的访问。同源策略要求资源必须来自同一个源(即协议、域名和端口相同),并限制了对以下内容的访问:

  1. Cookie、LocalStorage、IndexedDB 等存储性内容:不允许在不同源之间读取或写入这些数据。

  2. DOM 节点:不允许获取来自不同源的 DOM 元素。

  3. AJAX 请求发送后的响应数据:如果发起了跨域的 AJAX 请求,浏览器会阻止读取其响应内容。

但是有三个标签允许跨域加载资源,它们不受同源策略限制:

  • <img src=XXX>
  • <link href=XXX>
  • <script src=XXX>

常见跨域场景

跨域存在于协议、子域名、主域名、端口号中任何一个不相同时。即使两个不同的域名指向同一个 IP 地址,只要其中任何一部分不同,就被视为不同源。

两个重要点:

  1. 协议和端口造成的跨域问题需要后端处理,前端无法解决。
  2. 浏览器在判断跨域时主要依据 URL 的首部,即协议、域名和端口必须匹配。

跨域并不是指请求发不出去,而是浏览器限制了读取来自其他域名下内容的安全策略。例如,Ajax 请求会被浏览器拦截响应数据,但表单提交不会获取新内容,所以可以发起跨域请求。同样,跨域并不能完全阻止 CSRF,因为请求依然会发送出去,只是浏览器会拦截响应。

如何解决跨域

CORS

CORS 通信过程都是浏览器自动完成,需要浏览器(都支持)和服务器都支持,所以关键在只要服务器支持,就可以跨域通信,CORS请求分两类:简单请求和非简单请求。

CORS请求默认不包含Cookie以及HTTP认证信息,如果需要包含Cookie,涉及跨域请求携带 Cookie 信息时需要一些特殊设置,其中涉及到 CORS 的头部设置以及前端代码的配置。

假设有两个域名:https://example.com 和 https://api.example.com,前者是网页的域名,后者是提供 API 的域名。下面是一个示例,演示如何设置跨域请求以在包含 Cookie 的情况下进行:

后端设置 CORS 头部

在 API 的响应中设置 CORS 相关头部:

// Express 示例
const express = require('express');
const app = express();// 设置允许跨域请求的域名和允许携带 Cookie
app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', 'https://example.com');res.header('Access-Control-Allow-Credentials', 'true');next();
});// 处理其他路由或请求
// ...app.listen(3000);

前端发送带有 withCredentials 的请求

在前端,如果想要在跨域请求中携带 Cookie,需要在 XMLHttpRequest 或 Fetch 请求中设置 withCredentials 为 true

使用 XMLHttpRequest 的示例:

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.withCredentials = true; // 允许携带 Cookie
xhr.send();

或者使用 Fetch API:

fetch('https://api.example.com/data', {method: 'GET',credentials: 'include', // 允许携带 Cookie
});

上述代码中的关键点在于将 withCredentials 或 credentials: 'include' 设置为 true,这样浏览器就会在请求中包含当前页面的 Cookie 信息。但要确保后端 API 设置了正确的 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials 头部,并且不要使用 * 通配符,而是指定了明确的允许跨域的域名。

简单请求

简单请求指的是符合一定条件的跨域请求类型,在这种请求下,浏览器会自动在头部中添加 Origin 字段,表示请求的来源域,服务器根据这个来源决定是否允许请求。满足以下两个条件之一的请求被认为是简单请求:

1.请求方法是 HEAD、GET、POST 之一

2.请求头信息不超过一定限制。允许的请求头包括:

  • Accept

  • Accept-Language

  • Content-Language

  • Last-Event-Id

  • Content-Type:允许的值为 application/x-www/form/urlencoded、multipart/form-data、text/plain 之一。

这些条件主要为了兼容早期的表单提交方式,因为历史上表单提交一直可以跨域。

在这样的简单跨域请求中,服务器至少需要设置 Access-Control-Allow-Origin 头部来允许特定来源的请求。如果服务器认可请求,会在响应中返回以下必要的 CORS 头部:

Access-Control-Allow-Origin这个字段是必须的,它指定了允许访问的来源域,一般是请求中 Origin 字段的值,但也可以是通配符 *,表示允许任意来源。
Access-Control-Allow-Credentials这个字段是可选的,表示是否允许发送 Cookie。如果需要跨域请求携带身份凭证(比如 Cookie 或 HTTP 认证信息),服务器需要设置这个字段为 true。
Access-Control-Expose-Headers这个字段是可选的,它指定了响应中可以被前端访问的其他头部信息。
Content-Type表示响应的文档类型和字符编码。

简单请求的处理相对较为简单,但需要服务器允许特定的跨域访问并设置相应的 CORS 头部来确保安全。

非简单请求

非简单 CORS 请求指的是不符合简单请求条件的跨域请求,如使用了 PUT 或 DELETE 方法,或者请求的 Content-Type 是 application/json 等。对于这样的请求,浏览器会在正式发起请求之前先发送一个 OPTIONS 类型的预检请求。

预检请求的目的是向服务器查询是否允许来自网页所在域名的请求,并了解可以使用哪些额外的头信息字段。这个预检请求(OPTIONS 请求)的头部信息包括:

  • Origin: 标识请求来自哪个域,是必须的字段。
  • Access-Control-Request-Method: 列出 CORS 请求会用到的 HTTP 方法,也是必须的字段。
  • Access-Control-Request-Headers: 指定 CORS 请求会额外发送的头信息字段,用逗号隔开。

服务器收到这个预检请求后,根据收到的信息判断是否允许这个请求,如果允许,则返回相应的 CORS 头部信息。除了允许特定的跨域请求,服务器还可以在响应头部中添加 Access-Control-Max-Age 字段来缓存预检请求的结果,减少后续请求的预检次数。这个缓存只对完全一样的 URL 生效,超出缓存时间后,再次发起相同的跨域请求仍会触发预检请求。

Nginx代理跨域

Nginx可以用作反向代理服务器,来解决跨域问题。它可以代理客户端的请求,并将请求发送到目标服务器,再将目标服务器的响应返回给客户端。这种方法类似于 CORS 跨域原理,但是它是通过服务器端进行设置,而不是在浏览器端进行设置。

以下是一个简单的 Nginx 配置示例,用于处理跨域请求:

server {listen 81;server_name www.domain1.com;location / {# 设置反向代理proxy_pass http://xxxx1:8080;# 修改 Cookie 中的域名proxy_cookie_domain www.xxxx1.com www.xxxx2.com;# 添加头部信息以处理跨域请求add_header Access-Control-Allow-Origin http://www.xxxx2.com; # 当前端只跨域不带 Cookie 时,可以使用 * add_header Access-Control-Allow-Credentials true;}
}

这段配置的作用如下:

proxy_pass 指令用于指定反向代理的目标服务器地址。proxy_cookie_domain 用于修改代理服务器返回的响应中的 Cookie 中的域名,将它从源域名修改为目标域名,确保 Cookie 在跨域时仍然有效。add_header 指令用于添加响应头部信息,其中 Access-Control-Allow-Origin 允许特定来源的跨域请求,Access-Control-Allow-Credentials 表示是否允许请求携带身份凭证(例如 Cookie)。

这种方法通过 Nginx 作为代理服务器,处理了跨域请求的响应头部,允许指定的域名进行跨域请求。这样就可以在不修改前端代码的情况下,实现跨域请求的需求。

Node中间件代理跨域

在 vue.config.js 文件中,可以通过配置 devServer 的 proxy 选项实现代理转发:

module.exports = {// 其他配置...devServer: {proxy: {[process.env.VUE_APP_BASE_API]: {target: 'http://xxxx', // 代理跨域目标接口ws: true,changeOrigin: true,pathRewrite: {['^' + process.env.VUE_APP_BASE_API]: ''}}}}
}
  • proxy 字段用于配置代理。process.env.VUE_APP_BASE_API 是 Vue 项目中定义的环境变量,表示需要被代理的请求路径前缀。

  • target 指定了代理的目标地址,即请求将会被代理到这个地址下。

  • ws 表示是否代理 WebSocket。

  • changeOrigin 设置为 true 后,可以突破浏览器的同源策略,允许跨域。

  • pathRewrite 允许对请求路径进行重写,将匹配到的路径前缀去掉。比如,如果请求路径是 /api/user,经过 pathRewrite 后就会变成 /user,将前缀 /api 去掉了。

当使用 Node 中间件进行代理跨域时,你可以使用 http-proxy-middleware 包来创建一个代理服务器,让后端服务(如 Express)处理跨域请求。这个中间件可以在 Express 应用程序中使用,允许你在服务器端修改请求和响应,以便处理跨域问题。

下面是一个在 Express 中使用 http-proxy-middleware 中间件的简单示例:

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');const app = express();app.use('/', createProxyMiddleware({ // 代理跨域目标接口 target: 'http://xxxx:8080', changeOrigin: true, // 修改响应头信息,实现跨域并允许带cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://xxxx');res.header('Access-Control-Allow-Credentials', 'true');}, // 修改响应信息中的 cookie 域名 cookieDomainRewrite: 'www.domain1.com' // 可以为 false,表示不修改
})); app.listen(3000);

这段代码做了以下事情:

  • 引入了 Express 框架和 http-proxy-middleware。

  • 创建了一个 Express 应用。

  • 使用 app.use 将 createProxyMiddleware 中间件应用到根路径 /。

  • 配置了 createProxyMiddleware,指定了目标服务器的地址 target,开启了 changeOrigin 选项以确保源头地址被更改为目标地址。

  • 在 onProxyRes 中修改了响应头部信息,允许跨域并设置了允许携带凭证(如 Cookie)。

  • cookieDomainRewrite 可以用于修改响应信息中的 Cookie 域名,使其在传输中适应跨域情况。

这种方式可以在后端服务器层面对跨域进行处理,允许前端应用向不同域名的后端服务发出请求。

WebSocket

WebSocket是一种在单个 TCP 连接上进行全双工通信的协议,它允许客户端和服务器之间进行实时数据交换。与传统的 HTTP 请求不同,WebSocket 的连接是持久性的,双方可以随时发送数据而不需要等待请求。

在跨域方面,WebSocket协议与传统的 HTTP 请求不同,它不受同源策略的限制。可以使用 ws://(非加密)和 wss://(加密)作为协议前缀,不受同源策略的约束,只要服务器支持 WebSocket,即可与客户端进行通信。

WebSocket请求头中包含 Origin 字段,用于指示请求的来源域。服务器可以检查这个字段来判断是否允许与特定域的客户端建立 WebSocket 连接。如果客户端的来源域在服务器的白名单内,服务器将允许该连接的建立,否则可能会拒绝连接或执行其他安全措施。

通过 WebSocket,服务器和客户端之间可以进行持久的双向通信,这种通信方式适用于实时性要求较高的场景,如在线聊天、实时数据传输等。由于不受同源策略的限制,WebSocket提供了一种跨域通信的可选方案。

下面是一个简单的例子,展示了如何使用 WebSocket 进行跨域通信。

首先,假设有两个域名分别是 domain1.com 和 domain2.com,我们将在 domain1.com 的页面上创建 WebSocket 连接到 domain2.com 的服务器:

在 domain2.com 的服务器端,你需要有一个 WebSocket 服务器,例如基于 Node.js 的 ws 模块,用于监听 WebSocket 连接:

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: %s', message);// 可以回复客户端消息ws.send('Hello, client!');});
});

在 domain1.com 的页面上,你可以使用 JavaScript 来创建 WebSocket 连接到 domain2.com 的服务器:

const socket = new WebSocket('ws://domain2.com:8080'); // WebSocket服务器的地址socket.onopen = function(event) {console.log('WebSocket连接已打开');socket.send('Hello, server!');
};socket.onmessage = function(event) {console.log('收到服务器消息:', event.data);
};socket.onclose = function(event) {if (event.wasClean) {console.log('连接已关闭');} else {console.log('连接断开');}
};socket.onerror = function(error) {console.error('WebSocket连接错误:', error);
};

在这个例子中,domain1.com 的页面通过 WebSocket 连接到了 domain2.com 的服务器,并向其发送了消息。服务器收到消息后可以进行处理,并且也可以通过 WebSocket 向客户端发送消息。

需要注意的是,WebSocket 协议在设计上允许跨域通信,因此不会受到浏览器同源策略的限制。但是,服务器端仍然可以根据自己的逻辑来判断是否接受来自特定来源的连接。

postMessage

postMessage 是 HTML5 中的一项 API,它允许在不同窗口(包括 iframe)或不同来源的文档间进行安全地消息传递。这种通信机制可以用于多种场景:

1️⃣ 页面和新打开的窗口之间的数据传递

2️⃣ 不同窗口(包括不同域的窗口)之间的通信

3️⃣ 页面与嵌套的 iframe 之间的数据传递

4️⃣ 不同源的跨域传递数据

postMessage 接受两个参数:

第一个参数是要发送的数据,可以是字符串、对象等。

第二个参数是指定消息发送的目标窗口的来源。这个参数通常是一个目标窗口的 origin(协议 + 域名 + 端口),也可以是通配符 *(表示任意窗口),或者 /(表示与当前窗口同源的窗口)。

例如,在一个页面中,可以使用以下方式向另一个窗口发送消息:

// 获取目标窗口对象
const targetWindow = window.open('https://example.com', '_blank');// 向目标窗口发送消息
targetWindow.postMessage({ message: 'Hello, window!', value: 42 }, 'https://example.com');

在目标窗口中,可以监听 message 事件来接收来自其他窗口的消息:

// 监听 message 事件
window.addEventListener('message', function(event) {// 判断消息来源是否符合预期if (event.origin === 'https://sending-origin.com') {// 处理接收到的消息console.log('Received message:', event.data);}
});

JSONP

JSONP(JSON with Padding)是一种利用 <script> 标签实现的跨域数据请求方法。其原理是通过动态创建 <script> 标签,向服务器请求数据,并在请求的 URL 中包含一个回调函数名。服务器收到请求后,将数据包裹在回调函数中返回给客户端,从而绕过浏览器的同源策略限制。

JSONP 主要用于 GET 请求,并不适用于其他 HTTP 方法,且存在安全隐患,容易受到 XSS(跨站脚本攻击)的影响。但它有一些优点,比如可以向不支持 CORS 的旧浏览器或不支持跨域请求的网站请求数据。

使用 JSONP 的示例代码如下:

// 创建一个包含回调函数的 URL
const url = 'http://juejin.com/xxx?callback=handleCallback';// 创建一个 script 标签
const script = document.createElement('script');// 设置 script 的 URL
script.src = url;// 将 script 添加到页面中
document.body.appendChild(script);// 定义回调函数,处理从服务器返回的数据
function handleCallback(res) {console.log(res);
}

服务器接收到这个请求后,会将数据放在 handleCallback 函数中返回,例如:

handleCallback({ code: 200, msg: 'success', data: [] });

在客户端,这个函数 handleCallback 将立即执行,从而完成数据的处理和操作。

虽然 JSONP 具有一定的局限性和安全风险,但在某些场景下仍然是一种有效的跨域数据获取方式。

其他

除了以上提到的一些常见的解决跨域的方法以外,还有其他的方式可以来解决这个问题。

1. document.domain + iframe:适用于主域名相同但子域名不同的跨域场景。当两个页面的 document.domain 设置为同一个值(主域名),它们就可以相互通信。但这种方法仅适用于主域名相同的情况。

2. window.name + iframe:利用 iframe 的 window.name 属性,这个属性在不同页面或者不同域名加载后依然保持不变。通过在不同页面的 iframe 中设置和读取 window.name,可以实现跨域通信。window.name 具有持久性,且可以存储较大量的数据。

3. location.hash + iframe:适用于页面间利用 URL 的 hash 部分来传递信息,特别是在 C 页面帮助 A 页面和 B 页面进行通信。通过改变 URL 的 hash 部分来传递信息,在不同页面之间进行简单的数据交换。

这些方法虽然可以解决一些特定的跨域通信问题,但由于它们的特性和限制,通常只适用于特定场景,并且可能存在一些安全性或者容量方面的限制。因此,在使用这些方法时,需要仔细考虑其适用范围和可能带来的安全隐患。

好啦,本文就到这里结束了,感谢阅读~~

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

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

相关文章

2.6日学习打卡----初学RabbitMQ(一)

2.6日学习打卡 初识RabbitMQ、 一. MQ 消息队列 MQ全称Message Queue&#xff08;消息队列&#xff09;&#xff0c;是在消息的传输过程中保 存消息的容器。多用于系统之间的异步通信。 同步通信相当于两个人当面对话&#xff0c;你一言我一语。必须及时回复 异步通信相当于通…

数据库管理-第148期 最强Oracle监控EMCC深入使用-05(20240208)

数据库管理148期 2024-02-08 数据库管理-第148期 最强Oracle监控EMCC深入使用-05&#xff08;20240208&#xff09;1 性能主页2 ADDM Spotlight3 实时ADDM4 数据库的其他5 主机总结 数据库管理-第148期 最强Oracle监控EMCC深入使用-05&#xff08;20240208&#xff09; 作者&am…

【算法】{画决策树 + dfs + 递归 + 回溯 + 剪枝} 解决排列、子集问题(C++)

文章目录 1. 前言2. 算法例题 理解思路、代码46.全排列78.子集 3. 算法题练习1863.找出所有子集的异或总和再求和47.全排列II17.电话号码的字母组合 1. 前言 dfs问题 我们已经学过&#xff0c;对于排列、子集类的问题&#xff0c;一般可以想到暴力枚举&#xff0c;但此类问题用…

【flink状态管理(三)】StateBackend的整体设计、StateBackend创建说明

文章目录 一. 状态后端概述二. StateBackend的整体设计1. 核心功能2. StateBackend的UML3. 小结 三. StateBackend的加载与初始化1. StateBackend创建概述2. StateBackend创建过程 一. 状态后端概述 StateBackend作为状态存储后端&#xff0c;提供了创建和获取KeyedStateBacke…

006集——where语句进行属性筛选——arcgis

在arcgis中&#xff0c; dBASE 文件除了 WHERE 语句以外&#xff0c;不支持 其它 SQL 命令。选择窗口如下&#xff1a; 首先&#xff0c;我们了解下什么是where语句。 WHERE语句是SQL语言中使用频率很高的一种语句。它的作用是从数据库表中选择一些特定的记录行来进行操作。WHE…

Mybatis Day02

增删改查 环境准备 创建一个emp表创建一个新的springboot工程&#xff0c;选择mysql、lombok、mybatis依赖application.properties中引入数据库连接信息创建对应的实体类Emp准备Mapper接口EmpMapper&#xff0c;mapper代表程序运行时自动创建接口的代理对象&#xff0c;并放入…

第8节、双电机多段直线运动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;前面章节主要介绍了bresenham直线插值运动&#xff0c;本节内容介绍让两个电机完成连续的直线运动,目标是画一个正五角星 一、五角星图介绍 五角星总共10条直线&#xff0c;10个顶点。设定左下角为原点…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Blank组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Blank组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Blank组件 空白填充组件&#xff0c;在容器主轴方向上&#xff0c;空白填充组件具…

python-自动化篇-办公-一键将word中的表格提取到excel文件中

文章目录 代码 工作中&#xff0c;经常需要将Word文档中的表格粘贴到Excel文件中&#xff0c;以便汇总及分析。一个一个复制粘贴&#xff0c;非常不方便&#xff0c;还是Python自动化操作&#xff0c;省心省力。要求如下图所示&#xff0c;即将word中的所有表格&#xff0c;转存…

谷歌seo搜索引擎优化有什么思路?

正常做seo哪有那么多思路&#xff0c;其实就那么几种方法&#xff0c;无非就关键词&#xff0c;站内优化&#xff0c;外链&#xff0c;可以说万变不离其宗&#xff0c;但如果交给我们&#xff0c;你就可以实现其他的思路&#xff0c;或者说玩法 收录可以说是一个网站的基础&…

【C语言】三子棋游戏实现代码

目录 1.三子棋代码功能介绍 2.三子棋游戏实现步骤 ①打印菜单栏 ②判断是否进入三子棋游戏 ③三子棋游戏基本函数实现 &#xff08;1&#xff09;清空&#xff08;初始化&#xff09;棋盘函数实现 &#xff08;2&#xff09;打印棋盘函数实现 &#xff08;3&#xff0…

【JavaScript 漫游】【014】正则表达式通关

文章简介 JS 语言中的 RegExp 对象提供正则表达式的功能。本篇文章旨在对该对象的相关知识点进行总结。内容包括&#xff1a; 正则表达式概述RegExp 对象的实例属性RegExp 对象的实例方法字符串与正则表达式相关的实例方法正则表达式匹配规则 概述 正则表达式的概念 正则表…

Linux 【docker系列1 - docker 安装与使用】

系列文章目录 文章目录 系列文章目录前言一、docker安装二、常用使用1.镜像相关2.读入数据 总结 前言 一、docker安装 docker的官方文档写的非常的详细&#xff0c;它包含了docker在各种环境下的安装&#xff0c;以及可能遇到的问题和解决方案。这里我们只描述docker在contOS上…

PdfFactory Pro软件下载以及序列号注册码生成器

PdfFactory Pro注册机是一款针对同名虚拟打印机软件所推出的用户名和序列号生成器。PdfFactory Pro是一款非常专业的PDF虚拟打印软件&#xff0c;通过使用这款注册机&#xff0c;就能帮助用户免费获取注册码&#xff0c;一键激活&#xff0c;永久免费使用。 pdffactory7注册码如…

利用Python和pandas库进行股票技术分析:移动平均线和MACD指标

利用Python和pandas库进行股票技术分析&#xff1a;移动平均线和MACD指标 介绍准备工作数据准备计算移动平均线计算MACD指标结果展示完整代码演示 介绍 在股票市场中&#xff0c;技术分析是一种常用的方法&#xff0c;它通过对股票价格和交易量等历史数据的分析&#xff0c;来…

【MySQL】学习如何使用DCL进行用户管理

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-JwFD16F1Kh0fle0X {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

机器学习复习(8)——逻辑回归

目录 逻辑函数&#xff08;Logistic Function&#xff09; 逻辑回归模型的假设函数 从逻辑回归模型转换到最大似然函数过程 最大似然函数方法 梯度下降 逻辑函数&#xff08;Logistic Function&#xff09; 首先&#xff0c;逻辑函数&#xff0c;也称为Sigmoid函数&#…

备战蓝桥杯---搜索(进阶2)

话不多说&#xff0c;直接看题&#xff1a; 相当于找一个点使它到3个国家的距离和min,显然&#xff0c;我们不可以枚举点&#xff0c;但是&#xff0c;我们可以对这3个国家分别bfs&#xff0c;然后枚举相加即可。 下面是AC代码&#xff1a; #include<bits/stdc.h> usin…

02.05

1.单链表 main #include "1list_head.h" int main(int argc, const char *argv[]) { //创建链表之前链表为空Linklist headNULL;int n;datatype element;printf("please enter n:");scanf("%d",&n);for(int i0;i<n;i){printf("ple…

浅谈路由器交换结构

一、路由器技术概述 路由器&#xff08;Router&#xff09;是连接两个或多个网络的硬件设备&#xff0c;在网络间起网关的作用&#xff0c;是读取每一个数据包中的地址然后决定如何传送的专用智能性的网络设备。它能够理解不同的协议&#xff0c;例如某个局域网使用的以太网协议…