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

目录

什么是跨域

概念

同源策略及限制内容

常见跨域场景

如何解决跨域

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.mzph.cn/news/636391.shtml

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

相关文章

项目实战————苍穹外卖(DAY11)

苍穹外卖-day11 课程内容 Apache ECharts 营业额统计 用户统计 订单统计 销量排名Top10 功能实现&#xff1a;数据统计 数据统计效果图&#xff1a; 1. Apache ECharts 1.1 介绍 Apache ECharts 是一款基于 Javascript 的数据可视化图表库&#xff0c;提供直观&#x…

基于SpringBoot Vue养老院管理

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Gradle——基础

1、Gradle基础 1.1、Ant/Maven/Gradle对比 无论那种项目构建工具&#xff0c;都有自身的优势和劣势&#xff0c;所以选择一款最适合项目的就是最好的&#xff01; 1.2、Gradle项目目录结构 Gradle项目默认目录结构和Maven项目的目录结构一致&#xff0c;都是基于约定大于配置…

各种Linux版本安装Docker

文章目录 一、Ubuntu 20.04.61. 网卡和DNS配置2. Docker安装 二、CentOS Linux 7.91. 网卡和DNS配置2. Docker安装 三、Alibaba Cloud Linux 31. DNS配置2. repo说明3. Docker安装 四、验证是否安装成功 一、Ubuntu 20.04.6 1. 网卡和DNS配置 /etc/netplan 找到 *.yaml 文件 …

第十一站:C++面向对象-多态

为什么要使用多态 当定义的子类继承父类并重写父类的方法后, 父类使用指针调用子类的同名方法,得到的却是父类同名方法的结果 #include <iostream> using namespace std; class Father { public:void play() {cout << "一起去KTV唱歌吧" << end…

主板电路学习; 华硕ASUS A43S笔记本安装win7X64(ventoy)

记录 老爷机 白色 华硕 A43S 笔记本 安装 win7X64 1. MBR样式常规安装win7X64Sp1 (华硕 A43S 安装 win7X64 ) 老爷机 白色 华硕 A43S 笔记本 安装 win7X64 &#xff08;常规安装&#xff09; 设置&#xff1a; 禁用UEFI 启用AHCI ventoy制作MBR&#xff08;非UEFI&#xff…

OpenAI的DALL·e2生成的AI图像有时会带有偏见或NSFW

专家警告说&#xff0c;OpenAI的图像生成模型DALLe2可能玩起来很有趣&#xff0c;但它生成的图片可能会带有刻板印象和偏见&#xff0c;甚至是生成NSFW图片&#xff0c;因此在现实世界中部署会有风险。 OpenAI公司承认“如果没有足够的防护措施&#xff0c;像DALLe2这样的模型…

【Linux 内核源码分析】堆内存管理

堆 堆是一种动态分配内存的数据结构&#xff0c;用于存储和管理动态分配的对象。它是一块连续的内存空间&#xff0c;用于存储程序运行时动态申请的内存。 堆可以被看作是一个由各个内存块组成的堆栈&#xff0c;其中每个内存块都有一个地址指针&#xff0c;指向下一个内存块…

Wpf 使用 Prism 实战开发Day13

配置 AutoMapper 关系映射 在上一节 ToDoController 控制器&#xff0c;或 IToDoService 服务接口中&#xff0c;方法的传参都是直接传的实体类。但在实际开发过程中&#xff0c;这样是不允许的。标准且规范的做法是&#xff0c;定义一个数据传输层&#xff0c;即Dto层。 一.在…

51单片机矩阵键盘

矩阵键盘 矩阵键盘是一种常用于电子设备中的输入设备&#xff0c;其原理是利用行和列的交叉点来识别按键输入。矩阵键盘通常由多个按键排列成行和列的形式组成&#xff0c;通过按下某个按键可以在对应的行和列交叉点上产生电路连接。 在矩阵键盘中&#xff0c;每个按键都被安排…

【Linux】常见指令解析下

目录 前言1. cp指令&#xff08;重要&#xff09;2. mv指令 &#xff08;重要&#xff09;3. cat指令4. more指令5. less指令 &#xff08;重要&#xff09;6. head指令7. tail指令8. 时间相关的指令8.1 data显示8.2 时间戳 9. cal指令10. find指令&#xff08;非常重要&#x…

每日一练【最大连续1的个数】

一、题目描述 给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 二、题目解析 本题同样是利用滑动窗口的解法。 首先进入窗口&#xff0c;如果是1&#xff0c;就直接让right&#xff0c;但是如果是…

会话跟踪技术(cookiesession)

文章目录 1、什么是会话跟踪技术2、Cookie2.1、Cookie基本使用2.2、Cookie原理2.3、Cookie使用细节 3、Session3.1、Session基本使用3.2、Session原理3.3、Session使用细节 4、Cookie和Session的对比 1、什么是会话跟踪技术 会话 ​ 用户打开浏览器&#xff0c;访问web服务器的…

2024美赛数学建模思路 - 案例:感知机原理剖析及实现

文章目录 1 感知机的直观理解2 感知机的数学角度3 代码实现 4 建模资料 # 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 感知机的直观理解 感知机应该属于机器学习算法中最简单的一种算法&#xff0c;其…

cs231n assignment1——SVM

整体思路 加载CIFAR-10数据集并展示部分数据数据图像归一化&#xff0c;减去均值&#xff08;也可以再除以方差&#xff09;svm_loss_naive和svm_loss_vectorized计算hinge损失&#xff0c;用拉格朗日法列hinge损失函数利用随机梯度下降法优化SVM在训练集和验证集计算准确率&a…

产品经理 | 原型设计必须遵循的视觉设计规范(1)— 设计原则

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本系列原型设计规范教程&#xff0c;主要用于规范系统的原型界面设计&#xff0c;使之具有良好的设计风格&#xff0c;帮助塑造品牌形象。通过定义原型的字体、图标、布局、颜色等信息&#xff0c;提供多样化的交互设计方案…

无法找到mfc100.dll的解决方法分享,如何快速修复mfc100.dll文件

在日常使用电脑时&#xff0c;我们可能会碰到一些系统错误提示&#xff0c;比如“无法找到mfc100.dll”的信息。这种错误通常会阻碍代码的执行或某些应用程序的启动。为了帮助您解决这一问题&#xff0c;本文将深入探讨其成因&#xff0c;并提供几种不同的mfc100.dll解决方案。…

1360. 卒的遍历-深度优先搜索-DFS

代码&#xff1a; #include<bits/stdc.h> using namespace std; int n,m; int r[25][3]; int fx[3]{0,1,0}; int fy[3]{0,0,1}; int a; void print(int k){a;cout<<a<<":";for(int i1;i<k;i){cout<<r[i][1]<<","<<…

[C#]winform部署yolov8图像分类的openvino格式的模型

【官方框架地址】 https://github.com/ultralytics/ultralytics 【openvino介绍】 OpenVINO是一个针对Intel硬件优化的开源工具包&#xff0c;用于优化和部署深度学习模型。以下是OpenVINO部署模型的主要优点&#xff1a; 高性能&#xff1a;OpenVINO提供了一系列性能优化工…

Flask 3.x log全域配置(包含pytest)

最近使用到flask3.x&#xff0c;配置了全域的log&#xff0c;这边记录下 首先需要创建logging的配置文件&#xff0c;我是放在项目根目录的&#xff0c; Logging 配置 logging.json {"version": 1, # 配置文件版本号"formatters": {"default&qu…