九种 “姿势” 让你彻底解决跨域问题

本文深入解析了浏览器的同源策略及其对跨域访问的限制,详细介绍了包括JSONP、CORS、postMessage在内的多种跨域技术原理及应用场景,帮助开发者理解和应对跨域挑战。

在这里插入图片描述


阅读原文


同源策略

同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到 XSS、CSRF 等攻击。所谓同源是指 “协议 + 域名 + 端口” 三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。


什么是跨域?

当协议、域名、端口号,有一个或多个不同时,有希望可以访问并获取数据的现象称为跨域访问,同源策略限制下 cookielocalStoragedomajaxIndexDB 都是不支持跨域的。

假设 cookie 支持了跨域,http 协议无状态,当用户访问了一个银行网站登录后,银行网站的服务器给返回了一个 sessionId,当通过当前浏览器再访问一个恶意网站,如果 cookie 支持跨域,恶意网站将获取 sessionId 并访问银行网站,出现安全性问题;IndexDB、localStorage 等数据存储在不同域的页面切换时是获取不到的;假设 dom 元素可以跨域,在自己的页面写入一个 iframe 内部嵌入的地址是 www.baidu.com,当在百度页面登录账号密码时就可以在自己的页面获取百度的数据信息,这显然是不合理的。

这就是为什么 cookielocalStoragedomajaxIndexDB 会受到同源策略会限制,下面还有一点对跨域理解的误区:

误区:同源策略限制下,访问不到后台服务器的数据,或访问到后台服务器的数据后没有返回;
正确:同源策略限制下,可以访问到后台服务器的数据,后台服务器会正常返回数据,而被浏览器给拦截了。


实现跨域的方式

一、使用 jsonp 跨域

使用场景:当自己的项目前端资源和后端部署在不同的服务器地址上,或者其他的公司需要访问自己对外公开的接口,需要实现跨域获取数据,如百度搜索。

// 封装 jsonp 跨域请求的方法
function jsonp({ url, params, cb }) {
    return new Promise((resolve, reject) => {
        // 创建一个 script 标签帮助我们发送请求
        let script = document.createElement("script");
        let arr = [];
        params = { ...params, cb };

        // 循环构建键值对形式的参数
        for (let key in params) {
            arr.push(`${key}=${params[key]}`);
        }

        // 创建全局函数
        window[cb] = function(data) {
            resolve(data);
            // 在跨域拿到数据以后将 script 标签销毁
            document.body.removeChild(script);
        };

        // 拼接发送请求的参数并赋值到 src 属性
        script.src = `${url}?${arr.join("&")}`;
        document.body.appendChild(script);
    });
}

// 调用方法跨域请求百度搜索的接口
json({
    url: "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
    params: {
        wd: "jsonp"
    },
    cb: "show"
}).then(data => {
    // 打印请求回的数据
    console.log(data);
});

缺点:

  • 只能发送 get 请求 不支持 post、put、delete;
  • 不安全,容易引发 xss 攻击,别人在返回的结果中返回了下面代码。
`let script = document.createElement('script');
script.src = "http://192.168.0.57:8080/xss.js";
document.body.appendChild(script);`;

会把别人的脚本引入到自己的页面中执行,如:弹窗、广告等,甚至更危险的脚本程序。


二、使用 CORS 跨域

跨源资源共享/CORS(Cross-Origin Resource Sharing)是 W3C 的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

使用场景:多用于开发时,前端与后台在不同的 ip 地址下进行数据访问。

现在启动两个端口号不同的服务器,创建跨域条件,服务器(NodeJS)代码如下:

// 服务器1
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(3000);

// 服务器2
const express = require("express");
let app = express();
app.get("/getDate", function(req, res) {
    res.end("I love you");
});
app.use(express.static(__dirname));
app.listen(4000);

由于我们的 NodeJS 服务器使用 express 框架,在我们的项目根目录下的命令行中输入下面代码进行安装:

npm install express --save

通过访问 http://localhost:3000/index.html 获取 index.html 文件并执行其中的 Ajax 请求 http://localhost:4000/getDate 接口去获取数据,index.html 文件内容如下:

<!-- 文件:index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CORS 跨域</title>
</head>
<body>
    <script>
        let xhr = new XMLHttpRequest();

        // 正常 cookie 是不允许跨域的
        document.cookie = 'name=hello';

        // cookie 想要实现跨域必须携带凭证
        xhr.withCredentials = true;

        // xhr.open('GET', 'http://localhost:4000/getDate', true);
        xhr.open('PUT', 'http://localhost:4000/getDate', true);

        // 设置名为 name 的自定义请求头
        xhr.setRequestHeader('name', 'hello');

        xhr.onreadystatechange = function () {
            if(xhr.readyState === 4) {
                if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                    // 打印返回的数据
                    console.log(xhr.response);

                    // 打印后台设置的自定义头信息
                    console.log(xhr.getResponseHeader('name'));
                }
            }
        }
        xhr.send();
    </script>
</body>
</html>

上面 index.html 代码中发送请求访问不在同源的服务器 2,此时会在控制台给出错误信息,告诉我们缺少了哪些响应头,我们对应报错信息去修改访问的服务器 2 的代码,添加对应的响应头,实现 CORS 跨域。

// 服务器2
const express = require("express");
let app = express();

// 允许访问域的白名单
let whiteList = ["http://localhost:3000"];

app.use(function(req, res, next) {
    let origin = req.header.origin;
    if (whiteList.includes(origin)) {
        // 设置那个源可以访问我,参数为 * 时,允许任何人访问,但是不可以和 cookie 凭证的响应头共同使用
        res.setHeader("Access-Control-Allow-Origin", origin);
        // 想要获取 ajax 的头信息,需设置响应头
        res.setHeader("Access-Control-Allow-Headers", "name");
        // 处理复杂请求的头
        res.setHeader("Access-Control-Allow-Methods", "PUT");
        // 允许发送 cookie 凭证的响应头
        res.setHeader("Access-Control-Allow-Credentials", true);
        // 允许前端获取哪个头信息
        res.setHeader("Access-Control-Expose-Headers", "name");
        // 处理 OPTIONS 预检的存活时间,单位 s
        res.setHeader("Access-Control-Max-Age", 5);
        // 发送 PUT 请求会做一个试探性的请求 OPTIONS,其实是请求了两次,当接收的请求为 OPTIONS 时不做任何处理
        if (req.method === "OPTIONS") {
            res.end();
        }
    }
    next();
});

app.put("/getDate", function(req, res) {
    // res.setHeader('name', 'nihao'); // 设置自定义响应头信息
    res.end("I love you");
});

app.get("/getDate", function(req, res) {
    res.end("I love you");
});

app.use(express.static(__dirname));
app.listen(4000);

三、使用 postMessage 实现跨域

postMessage 是 H5 的新 API,跨文档消息传送(cross-document messaging),有时候简称为 XMD,指的是在来自不同域的页面间传递消息。

调用方式:window.postMessage(message, targetOrigin)

  • message:发送的数据
  • targetOrigin:发送的窗口的域

在对应的页面中用 message 事件接收,事件对象中有 dataoriginsource 三个重要信息

  • data:接收到的数据
  • origin:接收到数据源的域(数据来自哪个域)
  • source:接收到数据源的窗口对象(数据来自哪个窗口对象)

使用场景:不是使用 Ajax 的数据通信,更多是在两个页面之间的通信,在 A 页面中引入 B 页面,在 AB 两个页面之间通信。

与上面 CORS 类似,我们要创建跨域场景,搭建两个端口号不同的 Nodejs 服务器,后面相同方式就不多赘述了。

// 服务器1
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(3000);

// 服务器2
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(4000);

通过访问 http://localhost:3000/a.html,在 a.html 中使用 iframe 标签引入 http://localhost:4000/b.html,在两个窗口间传递数据。

<!-- 文件:a.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 A</title>
</head>
<body>
    <iframe src="http://localhost:4000/b.html" id="frame" onload="load()"></iframe>
    <script>
        function load() {
            let frame = document.getElementById('frame');
            frame.contentWindow.postMessage('I love you', 'http://localhost:4000');
            window.onmessage = function (e) {
                console.log(e.data);
            }
        }
    </script>
</body>
</html>
<!-- 文件:b.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 B</title>
</head>
<body>
    <script>
        window.onmessage = function (e) {
            // 打印来自页面 A 的消息
            console.log(e.data);
            // 给页面 A 发送回执
            e.source.postMessage('I love you, too', e.origin);
        }
    </script>
</body>
</html>

四、使用 window.name 实现跨域

同样是页面之间的通信,需要借助 iframe 标签,A 页面和 B 页面是同域的 http://localhost:3000,C 页面在独立的域 http://localhost:4000。

// 服务器1
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(3000);

// 服务器2
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(4000);

实现思路:在 A 页面中将 iframesrc 指向 C 页面,在 C 页面中将属性值存入 window.name 中,再把 iframesrc 换成同域的 B 页面,在当前的 iframewindow 对象中取出 name 的值,访问 http://localhost:3000/a.html。

<!-- 文件:a.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 A</title>
</head>
<body>
    <iframe src="http://localhost:4000/c.html" id="frame" onload="load()"></iframe>
    <script>
        // 增加一个标识,第一次触发 load 时更改地址,更改后再次触发直接取值
        let isFirst = true;
        function load() {
            let frame = document.getElementById('frame');
            if(isFirst) {
                frame.src = 'http://localhost:3000/b.html';
                isFirst = false;
            } else {
                console.log(frame.contentWindow.name);
            }
        }
    </script>
</body>
</html>
<!-- 文件:c.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 C</title>
</head>
<body>
    <script>
        window.name = 'I love you';
    </script>
</body>
</html>

五、使用 location.hash 实现跨域

window.name 跨域的情况相同,是不同域的页面间的参数传递,需要借助 iframe 标签,A 页面和 B 页面是同域的 http://localhost:3000,C 页面是独立的域 http://localhost:4000。

// 服务器1
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(3000);

// 服务器2
const express = require(express);
let app = express();
app.use(express.static(__dirname));
app.listen(4000);

实现思路:A 页面通过 iframe 引入 C 页面,并给 C 页面传一个 hash 值,C 页面收到 hash 值后创建 iframe 引入 B 页面,把 hash 值传给 B 页面,B 页面将自己的 hash 值放在 A 页面的 hash 值中,访问 http://localhost:3000/a.html。

<!-- 文件:a.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 A</title>
</head>
<body>
    <iframe src="http://localhost:4000/c.html#Iloveyou" id="frame"></iframe>
    <script>
        // 使用 hashchange 事件接收来自 B 页面设置给 A 页面的 hash 值
        window.onhashchange = function () {
            console.log(location.hash);
        }
    </script>
</body>
</html>
<!-- 文件:c.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 C</title>
</head>
<body>
    <script>
        // 打印 A 页面引入 C 页面设置的 hash 值
        console.log(location.hash);
        let iframe = document.createElement('iframe');
        iframe.src = 'http://localhost:3000/b.html#Iloveyoutoo';
        document.body.appendChild(iframe);
    </script>
</body>
</html>
<!-- 文件:b.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 B</title>
</head>
<body>
    <script>
        // 将 C 页面引入 B 页面设置的 hash 值设置给 A页面
        window.parent.parent.location.hash = location.hash;
    </script>
</body>
</html>

六、使用 document.domain 实现跨域

使用场景:不是万能的跨域方式,大多使用于同一公司不同产品间获取数据,必须是一级域名和二级域名的关系,如 www.baidu.com 与 video.baidu.com 之间。

const express = require("express");
let app = express();

app.use(express.static(__dirname));
app.listen(3000);

想要模拟使用 document.domain 跨域的场景需要做些小小的准备,到 C:\Windows\System32\drivers\etc 该路径下找到 hosts 文件,在最下面创建一个一级域名和一个二级域名。

127.0.0.1          www.domainacross.com
127.0.0.1          sub.domainacross.com

命名是随意的,只要是符合一级域名与 二级域名的关系即可,然后访问 http://www.domainacross.com:3000/a.html。

<!-- 文件:a.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面 A</title>
</head>
<body>
    <p>我是页面 A 的内容</p>
    <iframe src="http://sucess.domainacross.com:3000/b.html" onload="load()" id="frame"></iframe>
    <script>
        document.domain = 'domainacross.com';
        function load() {
            console.log(frame.contentWindow.message);
        }
    </script>
</body>
</html>
<!-- 文件:b.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>页面 B</title>
</head>
<body>
    <p>我是 B 页面的内容</p>
    <script>
        document.domain = 'domainacross.com';
        var message = 'Hello A';
    </script>
</body>
</html>

七、使用 WebSocket 实现跨域

WebSocket 没有跨域限制,高级 API(不兼容),想要兼容低版本浏览器,可以使用 socket.io 的库,WebSocket 与 HTTP 内部都是基于 TCP 协议,区别在于 HTTP 是单向的(单双工),WebSocket 是双向的(全双工),协议是 ws://wss:// 对应 http://https://,因为没有跨域限制,所以使用 file:// 协议也可以进行通信。

由于我们在 NodeJS 服务中使用了 WebSocket,所以需要安装对应的依赖:

npm install ws --save

<!-- 文件:index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>页面</title>
</head>
<body>
    <script>
        // 创建 webSocket
        let socket = new WebSocket('ws://localhost:3000');
        // 连接上触发
        socket.onopen = function () {
            socket.send('I love you');
        }
        // 收到消息触发
        socket.onmessage = function (e) {
            // 打印收到的数据
            console.log(e.data); // I love you, too
        }
    </script>
</body>
</html>
const express = require("express");
let app = express();

// 引入 webSocket
const WebSocket = require("ws");
// 创建连接,端口号与前端相对应
let wss = new WebSocket.Server({ port: 3000 });

// 监听连接
wss.on("connection", function(ws) {
    // 监听消息
    ws.on("message", function(data) {
        // 打印消息
        console.log(data); // I love you
        // 发送消息
        ws.send("I love you, too");
    });
});

八、使用 nginx 实现跨域

nginx 本身就是一个服务器,因此我们需要去 nginx 官网下载服务环境 http://nginx.org/en/download.html。

  • 下载后解压到一个文件夹中
  • 双击 nginx.exe 启动(此时可以通过 http://localhost 访问 nginx 服务)
  • 在目录新建 json 文件夹
  • 进入 json 文件夹新建 data.json 文件并写入内容
  • 回到 nginx 根目录进入 conf 文件夹
  • 使用编辑器打开 nginx.conf 进行配置

data.json 文件:

{
    "name": "nginx"
}

nginx.conf 文件:

server {
    .
    .
    .
    location ~.*\.json {
        root json;
        add_header "Access-Control-Allow-Origin" "*";
    }
    .
    .
    .
}

含义:

  • ~.*\.json:代表忽略大小写,后缀名为 json 的文件;
  • root json:代表 json 文件夹;
  • add_header:代表加入跨域的响应头及允许访问的域,* 为允许任何访问。

nginx 根目录启动 cmd 命令行(windows 系统必须使用 cmd 命令行)执行下面代码重启 nginx

nginx -s reload

不跨域访问:http://localhost/data.json

跨域访问时需要创建跨域条件代码如下:

// 服务器
const express = require("express");
let app = express();

app.use(express.static(__dirname));
app.listen(3000);

跨域访问:http://localhost:3000/index.html

<!-- 文件:index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>nginx跨域</title>
</head>
<body>
    <script>
        let xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://localhost/data.json', true);
        xhr.onreadystatechange = function () {
            if(xhr.readyState === 4) {
                if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                    console.log(xhr.response);
                }
            }
        }
        xhr.send();
    </script>
</body>
</html>

九、使用 http-proxy-middleware 实现跨域

NodeJS 中间件 http-proxy-middleware 实现跨域代理,原理大致与 nginx 相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置 cookieDomainRewrite 参数修改响应头中 cookie 中的域名,实现当前域的 cookie 写入,方便接口登录认证。

1、非 vue 框架的跨域(2 次跨域)
<!-- 文件:index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>proxy 跨域</title>
</head>
<body>
    <script>
        var xhr = new XMLHttpRequest();

        // 前端开关:浏览器是否读写 cookie
        xhr.withCredentials = true;

        // 访问 http-proxy-middleware 代理服务器
        xhr.open('get', 'http://www.proxy1.com:3000/login?user=admin', true);
        xhr.send();
    </script>
</body>
</html>

中间代理服务中使用了 http-proxy-middleware 中间件,因此需要提前下载:

npm install http-proxy-middleware --save-dev

// 中间代理服务器
const express = require("express");
let proxy = require("http-proxy-middleware");
let app = express();

app.use(
    "/",
    proxy({
        // 代理跨域目标接口
        target: "http://www.proxy2.com:8080",
        changeOrigin: true,

        // 修改响应头信息,实现跨域并允许带 cookie
        onProxyRes: function(proxyRes, req, res) {
            res.header("Access-Control-Allow-Origin", "http://www.proxy1.com");
            res.header("Access-Control-Allow-Credentials", "true");
        },

        // 修改响应信息中的 cookie 域名
        cookieDomainRewrite: "www.proxy1.com" // 可以为 false,表示不修改
    })
);

app.listen(3000);
// 服务器
const http = require("http");
const qs = require("querystring");

const server = http.createServer();

server.on("request", function(req, res) {
    let params = qs.parse(req.url.substring(2));

    // 向前台写 cookie
    res.writeHead(200, {
        "Set-Cookie": "l=a123456;Path=/;Domain=www.proxy2.com;HttpOnly" // HttpOnly:脚本无法读取
    });

    res.write(JSON.stringify(params));
    res.end();
});

server.listen("8080");
2、vue 框架的跨域(1 次跨域)

利用 node + webpack + webpack-dev-server 代理接口跨域。在开发环境下,由于 Vue 渲染服务和接口代理服务都是 webpack-dev-server,所以页面与代理接口之间不再跨域,无须设置 Headers 跨域信息了。

// 导出服务器配置
module.exports = {
    entry: {},
    module: {},
    ...
    devServer: {
        historyApiFallback: true,
        proxy: [{
            context: '/login',
            target: 'http://www.proxy2.com:8080',  // 代理跨域目标接口
            changeOrigin: true,
            secure: false,  // 当代理某些 https 服务报错时用
            cookieDomainRewrite: 'www.domain1.com'  // 可以为 false,表示不修改
        }],
        noInfo: true
    }
}

本篇文章在于帮助我们理解跨域,以及不同跨域方式的基本原理,在公司的项目比较多,多个域使用同一个服务器或者数据,以及在开发环境时,跨域的情况基本无法避免,一般会有各种各样形式的跨域解决方案,但其根本原理基本都在上面的跨域方式当中方式,我们可以根据开发场景不同,选择最合适的跨域解决方案。


源码下载地址: https://pan.quark.cn/s/a4b39357ea24 Altium Designer 18是一款功能丰富的电子设计自动化工具,其集成了电路原理图绘制、PCB布局规划、三维视图展示、电路仿真分析以及生产文件生成等多项核心功能,为电子工程师们提供了一个全面的硬件设计解决方案。该软件的官方中文指导材料系统地阐述了从项目初始阶段到最终完成的全过程操作方法。 在“AD18 官方中文指导材料”中,使用者可以掌握以下核心内容要点: 1. **系统配置与界面认知**:熟悉Altium Designer 18的工作平台,涵盖菜单选项、工具栏配置、工作区安排,以及个性化工作界面的设定方法。 2. **项目创建流程**:掌握如何建立新的项目工程,包括工程参数配置、项目模板选取,以及项目文件的添加操作。 3. **电路图绘制技术**:学习电路原理图的绘制流程,包括元件库的维护管理、元件放置技巧、连接线路绘制、属性编辑操作,以及网络表的自动生成方法。 4. **元件库构建与管理**:了解如何建立自定义元件库,执行元件的导入与导出任务,以及利用Altium Designer自带的元件资源库。 5. **PCB布局设计方法**:掌握PCB设计的基本准则,如元件布局策略、布线技巧、层叠结构调整、布线规则优化,以及冲突检测与短路处理技术。 6. **设计规范与约束条件**:理解设定设计规范和电气约束条件的关键性,包括间距参数设定、焊盘尺寸规格、过孔尺寸要求等,以及运用规则检查进行设计验证的流程。 7. **三维模型整合应用**:学习如何将三维模型与PCB设计内容相结合,以实现更为直观的机械配合验证。 8. **电路性能仿真技术**:掌握使用Altium Des...
源码链接: https://pan.quark.cn/s/a4b39357ea24 ### 接口测试知识要点说明 #### 一、接口测试的定义及分类 1. **概念阐释**: - 接口测试作为软件测试的关键环节,主要对系统之间的交互点进行验证。 - 它旨在核实接口的正确性、稳定性和功能性,保障各个系统组件能够依照预期执行交互操作。 2. **实施情境**: - 适用于多系统联合开发的环境。 - 适用于包含多个子系统的复杂应用系统开发过程。 3. **适用范围**: - 为其他系统提供支持的底层基础架构系统。 - 负责协调中心服务的系统架构。 4. **分类标准**: - **模块接口测试**:通常作为单元测试的一部分,适用于独立构建的功能模块。 - **Web接口测试**: - **服务端接口测试**:针对客户端与服务器端之间的接口进行验证。 - **外部接口测试**:对第三方提供的接口进行测试,例如支付平台提供的授权登录接口。 5. **测试角度**: - **接口功能验证**:核实接口功能是否满足预期要求。 - **接口性能评估**:衡量接口的处理能力及响应时间。 - **接口稳定性考察**:检测接口在长时间运行中的表现情况。 - **接口安全检测**:确保接口能够抵御非法访问或数据篡改。 6. **测试手法**: - **参数细致测试**:深入测试接口的输入参数和输出结果。 - **场景模拟测试**:依据实际业务场景进行测试验证。 #### 二、接口测试的详细流程 1. **测试规划**: - 明确测试范围、目标及所需资源。 - 规划测试策略,选择适宜的工具和技术手段。 2. **测试用例设计**: - 依据需求文档和接口规格文档设计测试用例。 - 覆...
内容概要:本文研究基于遗传算法(GA)与粒子群算法(PSO)相结合的无人机三维路径规划方法,旨在解决无人机在复杂三维环境中避障与路径优化的关键问题。通过构建包含障碍物、威胁区等约束的三维仿真环境,系统实现了GA与PSO两种智能优化算法的Matlab代码,并对其在路径规划中的性能进行全面对比分析,重点关注路径长度、飞行安全性、算法收敛速度等核心指标。研究充分利用GA的全局搜索能力与PSO的快速局部收敛特性,提出一种混合优化策略,有效克服单一算法易陷入局部最优或收敛缓慢的缺陷。文中不仅详细阐述了算法的设计流程、数学模型与实现细节,还提供了完整的仿真结果,验证了所提混合方法在复杂动态场景下的优越性、有效性和鲁棒性,为无人机自主导航提供了可靠的理论依据和技术方案。; 适合人群:具备一定Matlab编程基础和优化算法理论知识,从事无人机系统设计、智能控制、路径规划、人工智能应用等相关领研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于城市峡谷、山区、灾害救援等复杂三维环境中的无人机自主避障与最优任务路径规划;②为智能优化算法(GA、PSO及其混合策略)的学习、性能对比与工程化应用提供详实的实践案例和代码参考;③服务于高校科研教学、算法原型快速复现、以及在此基础上的进一步改进与创新研究。; 阅读建议:建议读者结合所提供的Matlab代码进行仿真运行与调试,深入理解两种算法的参数设置、适应度函数设计及路径生成机制,可通过修改环境地图、增加动态障碍物或调整优化目标函数等方式进行扩展性研究,以深化对算法本质和应用场景的理解。
内容概要:LTK8870S是一款单通道H桥有刷直流电机驱动器,支持6.5V至20V工作电压,具备3.0A峰值电流驱动能力,适用于打印机、家用电器及工业设备等机电一体化应用。该芯片采用PWM控制接口,可通过IN1和IN2逻辑输入实现电机正转、反转、滑行与制动等多种工作模式,并支持快衰减和慢衰减两种电流衰减方式以优化电机控制性能。器件集成电流调节功能,通过VREF引脚和外部检测电阻设定限流值,有效控制电机电流并降低系统功耗。同时具备低功耗休眠模式,在IN1和IN2均为低电平时自动进入,显著节省能耗。LTK8870S还集成了多重保护机制,包括VM欠压锁定(UVLO)、过温保护(TSD)、过流保护(OCP)及自动故障恢复功能,提升系统可靠性。其ESOP-8封装带裸露焊盘,利于散热,符合无铅环保标准。; 适合人群:电子硬件工程师、电机控制系统开发者、嵌入式系统设计人员,尤其适用于从事电机驱动电路设计的中级技术人员。; 使用场景及目标:①用于控制中小型有刷直流电机的正反转与调速;②应用于需要电流限制和节能休眠功能的电池供电设备;③作为工业自动化、智能家电或办公设备中的核心驱动模块;④帮助开发者理解H桥驱动、PWM调速、电流衰减模式及保护电路的设计原理。; 阅读建议:此资源技术细节丰富,建议结合典型应用电路图与电气参数表进行硬件设计参考,重点关注PWM控制逻辑、电流调节设置及保护机制的实现方式,并在实际应用中配合示波器调试输出波形与电流响应。
内容概要:本文提出了一种基于纳什谈判理论的风–光–氢多主体能源系统合作运行方法,旨在通过合作博弈框架协调风电、光伏与氢能系统之间的运行决策,实现多能源主体在满足个体理性前提下的整体效益最优。研究构建了考虑可再生能源出力随机性与氢能系统动态响应特性的多主体协同优化模型,采用纳什谈判机制设计利益分配规则,有效解决了各方在联合运行中的竞争与协作矛盾。通过Matlab平台完成了模型编程求解与仿真验证,结果表明该方法能够显著提升系统经济性、增强清洁能源消纳能力,并促进多主体间的合作意愿,为高比例可再生能源系统的市场化协同运行提供了理论依据与技术路径。; 适合人群:具备电力系统分析、优化建模与博弈论基础,从事新能源系统调度、综合能源系统规划与运行、能源市场机制设计等方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①研究风–光–氢多能互补系统的协同优化机制与利益分配策略;②构建基于合作博弈的综合能源系统运行模型并进行仿真分析;③支撑硕士、博士论文复现及高水平学术论文撰写与投稿。; 阅读建议:建议结合Matlab代码深入理解纳什谈判模型的数学建模过程,重点掌握目标函数构造、约束条件处理及均衡求解算法的实现细节,同时可尝试将其拓展至Shapley值等其他合作博弈方法的对比研究,以深化对多主体协同机制的理解。
源码下载地址: https://pan.quark.cn/s/2a998390025c 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源,包含带管理端功能的报名预约系统源代码。 微信小程序开发资源...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值