常言道,"讀萬卷書,不如行萬里路"。技術的學習也是如此,惟有實踐才能更清楚的明白原理和加深印象,所以本文會利用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就最好啦!=(//▽//)感謝你們~