假网站怎么制作,网站建设项目招标书,外贸网站建设设计,东乡族网站建设浏览器的同源策略是为了保护用户的安全#xff0c;限制了跨域请求。同源策略要求请求的域名、协议和端口必须完全一致#xff0c;只要有一个不同就会被认为是跨域请求。 本文列举了一些处理跨域请求的解决方案#xff1a; JSONPCORS跨域资源共享http proxynginx反向代理web… 浏览器的同源策略是为了保护用户的安全限制了跨域请求。同源策略要求请求的域名、协议和端口必须完全一致只要有一个不同就会被认为是跨域请求。 本文列举了一些处理跨域请求的解决方案 JSONPCORS跨域资源共享http proxynginx反向代理webSocket 协议跨域postMessagedocument.domain iframewindow.name iframelocation.hash iframe 1. JSONP
先说缺点JSONP只能处理get请求。
script、iframe、img、link 等src属性不存在跨域请求的限制。利用这个特性可以实现跨域请求 首先在服务器端用nodeexpress模拟一个接口
let express require(express);
let app express();app.listen(8001, (_) {console.log(服务器已启动!);
});app.get(/list, (req, res) {// let { callback Function.prototype } req.query;let callback req.query.callback;let data {code: 200,messsage: 程序猿小野,};res.send(${callback}(${JSON.stringify(data)}));
});1使用jquery的ajax实现axios的jsonp方法也可以
$.ajax({url: http://127.0.0.1:8001/list,method: get,dataType: jsonp, // 执行的JSONP的请求不加这一行会报跨域错误has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource.success: (res) {console.log(res);},
});
web本地启动的服务器地址是http://127.0.0.1:5501服务器的地址是http://127.0.0.1:8001/
不加dataType:jsonp时会报下面的跨域错误 2利用 script标签的src属性
function handleResponse(data) {console.log(接收到的数据, data);
}let scriptEle document.createElement(script);
scriptEle.src http://127.0.0.1:8001/list?callbackhandleResponse;
document.head.appendChild(scriptEle);
成功接收到数据 2. CORS跨域资源共享必须掌握
scriptaxios.get(http://127.0.0.1:8001/list).then((res) {console.log(res.data);}).catch((err) {console.error(err);});
/script let express require(express);
let app express();app.listen(8001, (_) {console.log(服务器已启动!);
});app.use((req, res, next) {res.header(Access-Control-Allow-Origin, http://127.0.0.1:5501);
// res.header(Access-Control-Allow-Origin, *);
// res.header(Access-Control-Allow-Credentials, true); // 后端允许发送Cookienext();
});app.get(/list, (req, res) {let data {code: 200,messsage: 程序猿小野,};res.send(${JSON.stringify(data)});
});3. http proxy 必须掌握
这种情况是目前开发时前端调试接口解决跨域问题最常见的处理方法。一般通过webpack webpack-dev-server实现。用vue-cli创建的项目可以在vue.config.js中配置。
index.js
import axios from axios;// axios.get(http://127.0.0.1:8001/user/list).then((res) {
axios.get(/user/list).then((res) {console.log(res);
});没有配置proxy代理时请求报错 vue.config.js配置示例
devServer: {open: true,port: 10003,headers: {Access-Control-Allow-Origin: *,},proxy: {/: {target: http://127.0.0.1:8001/,secure: false,changeOrigin: true,},},}, webpack.config.js 配置示例
let path require(path);
let HtmlWebpackPlugin require(html-webpack-plugin);
module.exports {mode: production,entry: ./src/index.js,output: {filename: bundle.min.js,path: path.resolve(__dirname, build)},devServer: {port: 3000,progress: true,contentBase: ./build,proxy: {/: {target: http://127.0.0.1:8001,changeOrigin: true},},},plugins: [new HtmlWebpackPlugin({template: ./src/index.html,filename: index.html,})],
};配置后请求成功 4. nginx反向代理必须掌握
nginx 相关的内容比较多有时间可以另开一个帖子去说。这里举一个我在实际开发过程中遇到的场景。我们的页面调其他前端模块的服务跨域了在开发中没有为什么上线后会出现呢。主要是因为开发时前端的服务都在同一个服务器上不会产生跨域情况。上线部署在不同的服务器这时候就出现了如下错误 修改ngnix的相关配置实际ip地址和对应的服务名已处理。修改后跨域问题解决
upstream testxxx {server 127.0.0.1:3000 weight1;server 127.0.0.2:4000 weight1;
}location /fuwuming{proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://testxxx/fuwuming;
}
查看结果 5. webSocket 协议跨域必须掌握
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信同时允许跨域通讯是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便下面案例借助了socket.io.js的库它很好地封装了webSocket接口提供了更简单、灵活的接口也对不支持webSocket的浏览器提供了向下兼容。
前端代码
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodydivuser inputinput typetext /button idbutton发送/button/divscript src./socket.io-4.7.2.js/scriptscriptvar socket io(http://127.0.0.1:3000);// 与服务器连接成功socket.on(connect, () {console.log(socket链接成功 socket.id);});// 接收服务器发送的消息socket.on(sendToClient, (message) {console.log(message);});let sendToServerFunc function () {let inputVal document.getElementsByTagName(input)[0].value;// 向服务器发送消息socket.emit(sendToServer, {message: 我是客户端: ${inputVal},});};document.getElementsByTagName(input)[0].onblur sendToServerFunc;document.getElementById(button).onclick sendToServerFunc;/script/body
/htmlnode服务器代码
// 导入express模块
const express require(express)
// 引入http创建服务器实例的方法
const {createServer} require(http)
const {Server} require(socket.io)
// 创建express的服务器实例
const app express()
// 创建http服务器实例
const httpServer createServer(app)
// 创建socket.io的实例
const io new Server(httpServer,{// 处理cors,解决跨域问题cors:{// origin: http://127.0.0.1:5500,//需要跨域资源共享的地址origin: http://127.0.0.1:5501,//需要跨域资源共享的地址allowedHeaders: [my-custom-header],credentials: true}
})
// 监听客户端连接回调函数会传递本次连接的socket
io.on(connection,(socket) {console.log(socket.id)// 监听到客户端发送的消息socket.on(sendToServer,(message) {console.log(message)// 向客户端发送消息socket.emit(sendToClient,{message:你好我是服务端让我们来聊天呀})})
} )// 调用listen方法指定端口号并启动web服务器
httpServer.listen(3000,() {console.log(server is running at http://127.0.0.1:3000)
})
效果如下 6. postMessage
MDN关于postMessage的介绍 测试案列
先用node启动两个服务器不同端口模拟跨域场景。 node serverA.js node serverB.js let express require(express);
let app express();app.listen(1001, (_) {console.log(服务器A已启动!);
});app.use(express.static(./));
let express require(express);
let app express();app.listen(1002, (_) {console.log(服务器B已启动!);
});app.use(express.static(./));
A.html
!DOCTYPE html
html langen
headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title
/head
bodyh1A 页面/h1iframe idiframe srchttp://127.0.0.1:1002/B.html frameborder0 styledisplay: none;/iframescriptiframe.onload function () {iframe.contentWindow.postMessage(这是A页面传过来的数据AAA, *);}// 监听B页面传递的消息window.onmessage function(res){console.log(res);}/script
/body
/html
B.html
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyh1B 页面/h1script// 监听A页面传递的消息window.onmessage function (res) {console.log(res);res.source.postMessage(这是B页面传过来的数据BBB, res.origin);};/script/body
/html下面几种方案只做了解实际上几乎用不到。
7. document.domain iframe 只做了解
此方案只能实现同一个主域不同子域之间的操作
比如http://www.domain.com/a.html 和 http://child.domain.com/b.html 属于同一个主域
iframe idiframe srchttp://child.domain.com/b.html/iframe
scriptdocument.domain domain.com;var user admin;
/script
scriptdocument.domain domain.com;// 获取父窗口中变量console.log(window.parent.user);
/script
8. window.name iframe只做了解
三个页面A.html地址为http://127.0.0.1:1001/A.html
B.html地址为http://127.0.0.1:002/B.html
Proxy.html地址为http://127.0.0.1:1002/proxy.html
可以看出B页面和Proxy页面同源A想访问B的数据就跨域了
B.html的代码可以看到B.html的window对象上有一个name属性
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyscript// 服务器端需要返回给A的信息都在window.name中存储window.name 这是B页面的数据;/script/body
/html!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyiframeidiframesrchttp://127.0.0.1:1002/B.htmlframeborder0styledisplay: none/iframescriptiframe.onload function () {// 直接读不允许console.log(iframe.contentWindow.name);};/script/body
/html直接读不允许控制报跨域错误 将iframe的src属性修改成和B.html同域的Proxy.html地址
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyiframeidiframesrchttp://127.0.0.1:1002/B.htmlframeborder0styledisplay: none/iframescriptlet count 0;iframe.onload function () {// 直接读不允许// console.log(iframe.contentWindow.name);// 需要我们先把地址重新指向到同源中才可以// iframe.src http://127.0.0.1:1001/proxy.html;// 只要proxy.html中的window没有name属性那么这里就会取到B.html中window.name// console.log(iframe.contentWindow.name);if (count 0) {iframe.src http://127.0.0.1:1001/proxy.html;count;return;}console.log(iframe.contentWindow.name);};/script/body
/html在A.html中成功读取到B.html的数据 9. location.hash iframe只做了解
A和C同源A和B非同源
A.html
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyiframeidiframesrchttp://127.0.0.1:1002/B.htmlframeborder0styledisplay: none/iframescriptlet iframe document.getElementById(iframe);iframe.onload function () {iframe.src http://127.0.0.1:1002/B.html#msghello;};// 开放给同域C.html的回调方法function func(res) {console.log(res);}/script/body
/htmlB.html
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyiframeidiframesrchttp://127.0.0.1:1001/C.htmlframeborder0styledisplay: none/iframescriptlet iframe document.getElementById(iframe);// 监听A传来的HASH值改变再传给C.htmlwindow.onhashchange function () {iframe.src http://127.0.0.1:1001/C.html location.hash;};/script/body
/htmlC.html
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyscript// 监听B传来的Hash值window.onhashchange function () {// 再通过操作同域A的js回调将结果传回window.parent.parent.func(location.hash);};/script/body
/html如果还有其他方案欢迎留言补充。
总结一下2、3、4、5 我个人觉得是必须要掌握的因为我在实际的项目开发中都使用过。