常言道,"读万卷书,不如行万里路"。技术的学习也是如此,惟有实践才能更清楚的明白原理和加深印象,所以本文会利用node.js对前端的各类跨域方式进行实践,强烈建议一步一步跟着作,相信你确定会对跨域有更深层次的理解。而因为篇幅限制,本文只会贴出关键性的代码,本系列总共分为上下篇。具体的代码请移步个人Github。若是对你有帮助的话,欢迎 star ヾ(´・ω・`)ノhtml
接上文--->「跨域」利用node.js实践前端各类跨域方式(上)前端
postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数很少能够跨域操做的window属性之一,它可用于解决如下方面的问题:html5
1.页面和其打开的新窗口的数据传递
2.多窗口之间消息传递
3.页面与嵌套的iframe消息传递
4.上面三个场景的跨域数据传递node
用法:postMessage(data,origin)
方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,因此传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也能够设置为"*",表示能够传递给任意窗口,若是要指定和当前窗口同源的话设置为"/"。nginx
来,咱们来用node.js实践一下~git
目录:postMessage/public/a.htmlgithub
<!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>a</title> <iframe id="iframe" src="http://localhost:4444/b.html" style="display:none;"></iframe> </head> <body> <script> const iframe = document.getElementById('iframe'); iframe.onload = function() { const data = { name : 'Jchermy' }; //向http://localhost:4444 发送跨域数据 iframe.contentWindow.postMessage(JSON.stringify(data), "http://localhost:4444"); }; //接受 localhost:4444 返回的数据 window.addEventListener('message', function(e){ alert('data from b.html ----->' + e.data); },false); </script> </body> </html>
在iframe加载完成后,向b.html所在域发送数据。由于postMessage是绑定在window对象上的,因此咱们要获取iframe.contentWindow再发送数据,同时监听message
,观察b.html有没有回传数据给咱们。如今分别跑两个服务。访问localhost:3333能够看到:web
b.html接收到a.html发送过去的数据啦~ajax
而后a.html也收到了b.html回传的数据了。express
跨域成功~ ( 。ớ ₃ờ)ھ
这个方案的原理图以下:
说明:当A域想与B域通讯,能够经过nginx的反向代理,首先A域与同域的nginx服务器通讯,而后nginx将请求转发到另一个服务器,由于服务器之间的通讯不存在跨域,这样咱们就完成了跨域。具体实现以下:
首先,若是本地没有安装nginx的,须要安装nginx。安装完成后,咱们对nginx进行配置:
目录:nginx-1.14.0/conf/nginx.conf
server { listen 1111; server_name localhost; location / { proxy_pass http://localhost:9999/; #反向代理到9999端口 index index.html index.htm; default_type "text/html"; alias "D:/Github/node-server/nginx/public/"; #client.html所在的本地的地址 add_header Access_Control_Allow_Origin http://localhost:1111; add_header Access_Control_Allow_Credentials true; #容许客户端带cookie访问 }
而后,咱们配置9999端口的服务器
目录:nginx/server.js
const http = require('http'); const server = http.createServer(); const qs = require('querystring'); server.on('request', function(req, res) { const query = require('url').parse(req.url, true).query; //向前台写cookie res.writeHead(200, { 'Set-Cookie' : 'name=jchermy;Path:/;Domain:localhost;Httponly' //HttpOnly 脚本没法读取 }); res.write(JSON.stringify('Hi! '+query.user)); res.end(); }) server.listen('9999'); console.log('Server is running at port 9999 .....');
这时候,咱们打开浏览器,访问 http://localhost:1111/client.html?user=jchermy,看到下面的页面:
咱们在1111端口,将user=jchermy
传给9999端口,而后9999端口接收到了咱们的发送的信息并回传了"Hi! jchermy"
.说明这两个url能够跨域相互通讯!完成~
这个方案与nginx反向代理十分相似,只是将nginx代理服务器换成了node服务器。
目录:node-middleware/proxyserver.js
const express = require('express'); const proxy = require('http-proxy-middleware'); const app = express(); app.use('/login', proxy({ //代理跨域的目标接口 target: 'http://localhost:5555', changeOrigin: true, //修改响应头信息,实现跨域,并容许带cookie onProxyRes: function(proxyRes, req, res) { res.header('Access-Control-Allow-Origin', 'http://localhost'); res.header('Access-Control-Allow-Credentials', 'true'); }, //修改响应信息中的cookie域名 cookieDomainRewrite: 'http://localhost' })); app.use(express.static( './public')); app.listen(3333); console.log('proxy server is listen at port 3333');
目录:node-middleware/server.js
const http = require('http'); const server = new http.Server(); const qs = require('querystring'); server.on('request', function(request, response) { const query = require('url').parse(request.url, true).query; response.writeHead(200, { 'Set-Cookie': 'name=amiee;Path:/;Domain:localhost:3333;Httponly' }); response.write(`Hi, ${query.name} ! I come from localhost:5555`); response.end(); }) server.listen('5555'); console.log('Server is running at port 5555 .....')
最后,访问http://localhost:3333/login?name=hahah,能够看到:
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通讯,同时容许跨域通信,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,咱们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
首先,咱们建立一个客户端的html页面。
目录:webSocket/public/index.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>index</title> </head> <body> <div>用户输入: <input type="text"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script> <script> window.onload = function(){ var socket = io('http://localhost:5555'); //链接成功处理 socket.on('connect', function(){ console.log('Server socket has established'); }); socket.on('disconnect', function() { console.log('Server sockect has closed'); }); //监听服务端消息 socket.on('message', function(msg) { console.log('data from server ---->' +msg); } ) document.getElementsByTagName('input')[0].onblur = function() { socket.send(this.value); }; } </script> </body> </html>
将这个页面部署在3333端口上。
目录:webSocket/client.js
const express = require('express'); const app = express(); app.use(express.static('./public')); app.listen(3333); console.log('client is running at port 3333....');
最后,建立一个服务器,接收客户端的请求,并给予返回值
目录: webSocket/server.js
const http = require('http'); const socket = require('socket.io'); //启动http服务 const server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html' }); res.end(); }) server.listen(5555); console.log('server is running at port 5555'); const io = socket(server); //监听socket链接 io.on('connection', function (client) { //接收消息 client.on('message', function (msg) { io.emit('message', `hello, ${msg}`); console.log('data from client --->' + msg); }); //断开处理 client.on('disconnect', function() { console.log('Client socket has closed'); }); });
将客户端和服务器端都跑起来,输入一些字符,当鼠标失去焦点后能够在服务器端5555端口的控制台看到:
这说明服务器已经收到了客户端发送过去的字符。
此时在打开客户端页面的控制台,能够看到客户端也收到了服务器返回的字符:
这个系列终于写完啦,仍是那句话,有错误和不合理的地方欢迎你们指正!若是文章对你有帮助的话,欢迎点赞和收藏!!Github给个star就最好啦!=(//▽//)感谢你们~