跨域是一個咱們常常遇到的問題,特別是當服務有兩個域名的時候,若是你的頁面是在
a.test.com
,而後須要向b.test.com
請求數據,這個時候就存在跨域的問題了。若是你直接請求,你就會發現瀏覽器就直接報錯了,這個時候就要了解什麼是 同源策略 了。javascript
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互,這是一個用於隔離潛在惡意文件的關鍵安全機制。css
協議、域名與端口。這三者任何一個不同的話,就算是不一樣源,就會產生跨域的問題。html
不是一個源的文檔,就沒有權限去操做另外一個源的文檔。前端
Cookie、LocalStorage 和 IndexDB沒法讀取。java
Dom沒法得到node
Ajax請求不能發送jquery
舉個簡單的例子,咱們登錄是須要帶上 cookie
的,好比咱們登陸了一個銀行網站,那麼咱們的瀏覽器中則會帶上相應的 cookie
,下次咱們這個銀行網站的時候,若是這個 cookie
還存在的話,就能夠不須要登陸了;webpack
若是瀏覽器沒有同源策略,那麼一些不法分子能夠拿到咱們瀏覽器的 cookie
從而進咱們的銀行帳號取錢,這是很是可怕的事情。nginx
這就是瀏覽器要有同源策略的緣由。git
URL 說明 是否容許通訊
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不一樣文件或路徑 容許
http://www.domain.com/lab/c.js
http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不一樣端口 不容許
http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不一樣協議 不容許
http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名對應相同ip 不容許
http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不一樣 不容許
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js 不一樣域名 不容許
複製代碼
由於瀏覽器存在跨域這個問題,可是咱們平時在開發過程當中,有不少場景須要用到跨域通訊,好比前端和後端的接口源不是同一個的時候,這個時候咱們就須要進行跨域通訊了。
jsonp
CORS
:跨域資源共享postMessage
:HTML5
提供的 api
Hash
:不一樣源能夠訪問 hash
window.name
:不一樣的頁面(甚至不一樣域名)加載後依舊存在document.domain
:主域相同的狀況websocket
:HTML5
提供的新的協議webpack
:等構建構建工具中提供的跨域解決辦法nginx
:這個屬於後端的,筆者在本文就不作詳細介紹了,你們能夠自行找相關資料,其實也蠻簡單的接下來咱們來詳細講一下這幾種解決跨域問題的通訊方式,全部代碼都會放在這個倉庫中:跨域通訊 示例代碼。
一般爲了減輕 web
服務器的負載,咱們把 js
、css
,img
等靜態資源分離到另外一臺獨立域名的服務器上,在html
頁面中再經過相應的標籤從不一樣域名下加載靜態資源,而被瀏覽器容許。
基於此原理,咱們能夠經過動態建立 script
,再請求一個帶參網址實現跨域通訊。
咱們新建 jsonp
文件夾,並新建三個文件
jsonp
方法,jsonp
其實就是新建一個 script
文件,由於咱們上面也講到了 script
是不會跨域的,接着將須要請求的連接放在 script
的 src
中,同時在 window
上掛一個全局 callback
方法,後端返回的時候會將你要的數據放在這個 callback
的參數中,這個時候你就能夠獲得這些數據了。function jsonp ({ url, params, cb }) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
// 全局掛一個方法
window[cb] = function(data) {
resolve(data);
document.body.removeChild(script);
}
// 將 cb 放在 params 中
params = { ...params, cb};
let arrs = [];
// 將 params 中的 key 拼成相似 a=1 形式
for(let key in params) {
arrs.push(`${key}=${params[key]}`);
}
// 開始拼 url,目標結果 a=1&b=2&c=3
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
})
}
複製代碼
express
來起一個 Node.js
服務,接下去其餘項目的例子筆者也會使用相似於下面這個 js
來啓動服務,若是是增長方法我會特別標出:let express = require('express');
let app = express();
// 以當前目錄做爲服務器靜態目錄
// 咱們能夠經過 localhost:3000/index.html 訪問 html 文件
app.use(express.static(__dirname));
app.get('/jsonp', function(req, res) {
// 準備放回給前端的數據
const data = {
data: '我是 jsonp 的 data',
}
// 獲取前端傳的 cb 方法
const { cb } = req.query;
// 設置輸出的 html 格式爲 utf-8
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})
if (cb) {
// 若是有 cb 參數,就講 data 返回給前端
res.end(`${cb}(${JSON.stringify(data)})`);
} else {
// 若是沒有 cb,就返回錯誤
res.end('未傳 callback 參數');
}
})
app.listen(3000, () => {
console.log('服務器已經在3000端口啓動');
});
複製代碼
jsonp
例子 html
文件,發 jsonp
的請求...
<body>
<h1>Jsonp 的 demo</h1>
<script src="./jsonp.js"></script>
<script> jsonp({ url: 'http://localhost:3000/jsonp', params: { key: '1', }, cb: 'showData', }).then((data) => { console.log('data', data); }) </script>
</body>
...
複製代碼
咱們在根目錄下運行一下 node ./jsonp/server.js
,訪問 localhost:3000
:
能夠看到在頁面中顯示了 index.html
的內容,同時在控制檯輸出了相應的 data
:
在 jquery
中已經幫咱們封裝好了,直接使用便可,但須要先引入 jquery
,可使用 $.ajax
規定 dataType
,具體筆者也不演示了,使用以下:
// ...
$.ajax({
url: 'http://localhost:3000/jsonp',
type: 'get',
dataType: 'jsonp', // 請求方式爲jsonp
success:function(ret){
console.log(ret);
}
});
複製代碼
使用起來很簡單,兼容性好,能兼容一些遠古瀏覽器。可是他只支持 GET
請求,同時會有安全的問題,可能會被 xss
注入。
CORS
是一個 W3C
標準,全稱是"跨域資源共享"(Cross-origin resource sharing
)。它容許瀏覽器向跨源發送 XMLHttpRequest
,主要在後端服務器中增長一些相關配置便可,但有的時候須要前端進行一些配合,接下來我會講幾個經常使用的配置:
咱們新建 cors
文件夾,並新建四個文件,一個 html
文件,兩個服務器文件,一個本身的服務器文件,一個目標服務器文件,用來咱們作請求使用;一個簡單封裝的 ajax.js
文件:
這裏寫了一個簡單的 ajax
,具體就不細講了,你們想深刻研究能夠參考:Ajax 知識體系大梳理。
function ajax( methods, url ) {
// 新建一個 xhr 實例
// 在這裏沒有兼容 IE6, IE5,
// IE6,IE5 可使用 newActiveXObject("Microsoft.XMLHTTP");
const xhr = new XMLHttpRequest();
// 初始化一個請求
// methods:請求類型
// url:連接
// async:是否異步,true (異步); false(同步)
xhr.open(methods, url, true);
// 只要 readyState 屬性發生變化
// 狀態變化的監聽函數
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
// 返回成功的時候,輸出相應的 response
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
}
}
}
xhr.send();
}
複製代碼
server
文件這個文件和 jsonp
的 server.js
同樣,在 3000
端口開啓一個服務器,讓咱們的 index.html
可以在 localhost:3000/index.html
訪問。
這個文件是目標服務器文件,端口號 4000
,用來咱們發送 ajax
請求,這裏咱們增長了一個 getData
方法:
// ...
app.get('/getData', function(req, res) {
const data = {
data: '我是 cors 的 data',
}
res.end(JSON.stringify(data));
})
// ...
複製代碼
html
文件用來發送 ajax
請求:
...
<body>
<h1>Cors demo</h1>
<script src="./ajax.js"></script>
<script> ajax('GET', 'http://localhost:4000/getData'); </script>
</body>
...
複製代碼
接下來咱們啓動兩個服務,訪問一下 localhost:3000/index.html
發現有一個報錯:
這時咱們就須要在後端配置 CORS
了。
咱們能夠修改一下 server2.js
,增長 Access-Control-Allow-Origin
這個頭,通常來講咱們改爲 *
,就能解決這個問題了,可是在項目中,咱們可能須要設置一個白名單,規定哪些源能夠訪問,咱們能夠作以下配置:
let whiteList = ['http://localhost:3000']
// exprss 的一箇中間件,全部的路由都會走一下
app.all('*', function (req, res, next) {
// 獲取請求的源
let origin = req.headers.origin;
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
} else {
// 不在白名單中 返回
res.end('你不在白名單中');
}
// 繼續執行
next();
});
複製代碼
這個時候咱們從新運行 server2.js
,咱們就能拿到相應的值了:
咱們再來介紹幾個經常使用的配置:
若是用戶想要在頭部設置一些值,則在後端須要定義這個頭,它也是一個逗號分隔的字符串,代表服務器支持的全部頭信息字段。若是不定義會報以下錯誤:
若是咱們想要在 header
中增長 name=darrell
,咱們在 ajax.js
中新增以下代碼:
//...
xhr.open(methods, url, true);
// ...
xhr.setRequestHeader('name', 'darrell'); // 增長一個頭
// ...
xhr.send();
複製代碼
在 servers.js
增長:
// ...
app.all('*', function (req, res, next) {
// ...
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
// 容許前端攜帶哪一個頭訪問我
res.setHeader('Access-Control-Allow-Headers', 'name,key');
}
// ...
});
複製代碼
它的值是逗號分隔的一個字符串,代表服務器支持的全部跨域請求的方法。若是個人請求方法爲 put
,不設置次字段會報錯:
在 server.js
中增長此頭:
app.all('*', function (req, res, next) {
// ...
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
// 容許前端攜帶哪一個頭訪問我
res.setHeader('Access-Control-Allow-Headers', 'name,key');
// 容許哪一個方法訪問
res.header("Access-Control-Allow-Methods","PUT");
}
// ...
});
複製代碼
它的值是一個布爾值,表示是否容許發送 Cookie
。默認狀況下,Cookie
不包括在 CORS
請求之中。設爲 true
,即表示服務器明確許可,Cookie
能夠包含在請求中,一塊兒發給服務器。
若是在瀏覽器端設置了容許攜帶 cookie
:xhr.withCredentials = true;
,那麼必需要在後端設置這個頭,否則會以下錯:
在 server.js
中增長此頭:
app.all('*', function (req, res, next) {
// ...
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
// 容許前端攜帶哪一個頭訪問我
res.setHeader('Access-Control-Allow-Headers', 'name,key');
// 容許哪一個方法訪問
res.header("Access-Control-Allow-Methods","PUT");
// 容許攜帶 cookie
res.header("Access-Control-Allow-Credentials", true);
}
// ...
});
複製代碼
CORS
請求時,XMLHttpRequest
對象的 getResponseHeader()
方法只能拿到6個基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。若是想拿到其餘字段,就必須在 Access-Control-Expose-Headers
裏面指定。
好比我要在 ajax
的 response
中取返回頭中的 name
:
// ...
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
console.log(xhr.getResponseHeader('name'));
}
}
// ...
複製代碼
同時在 getData
這個接口寫一個 name
上去:
app.get('/getData', function(req, res) {
// ...
res.setHeader('name', 'maolei');
// ...
})
複製代碼
若是後端沒有設置次頭,則會有以下報錯:
在 server.js
中增長此頭:
app.all('*', function (req, res, next) {
// ...
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
// 容許前端攜帶哪一個頭訪問我
res.setHeader('Access-Control-Allow-Headers', 'name,key');
// 容許哪一個方法訪問
res.header("Access-Control-Allow-Methods","PUT");
// 容許攜帶 cookie
res.header("Access-Control-Allow-Credentials", true);
// 容許前端獲取哪一個頭
res.header("Access-Control-Expose-Headers", 'name');
}
// ...
});
複製代碼
用來指定本次預檢請求的有效期,單位爲秒。預檢請求指的是瀏覽器針對於複雜請求的時候,會在正式通訊以前,增長一次HTTP查詢請求(option
),稱爲 預檢請求。咱們能夠設置這個請求的有效期:
app.all('*', function (req, res, next) {
// ...
if (whiteList.includes(origin)) {
// 設置哪一個源訪問
res.setHeader('Access-Control-Allow-Origin', origin);
// 容許前端攜帶哪一個頭訪問我
res.setHeader('Access-Control-Allow-Headers', 'name,key');
// 容許哪一個方法訪問
res.header("Access-Control-Allow-Methods","PUT");
// 容許攜帶 cookie
res.header("Access-Control-Allow-Credentials", true);
// 容許前端獲取哪一個頭
res.header("Access-Control-Expose-Headers", 'name');
// 用來指定本次預檢請求的有效期,單位爲秒
res.header("Access-Control-Max-Age","6");
}
// ...
});
複製代碼
更多的請求,筆者在這裏就不講了,你們能夠參考阮一峯老師的 跨域資源共享 CORS 詳解
CORS
請求是比較安全的,並且支持全部類型的 HTTP
請求,配置起來也相對比較方便;開發者可使用普通的 XMLHttpRequest
發起請求和得到數據,比起 JSONP
有更好的錯誤處理;並且在絕大多數現代瀏覽器都已經支持了 CORS
,若是業務中不須要兼容遠古瀏覽器的,就能夠放心的使用 CORS
了。
postMessage
是 HTML5
中的API,且是爲數很少能夠跨域操做的 window
屬性之一,它可用於解決如下方面的問題
opener
來進行通行。iframe
消息傳遞這裏咱們就來舉一個 iframe
嵌套的例子:
咱們新建 postmessage
文件夾,並新建四個文件,兩個不一樣源 html
文件,兩個服務器文件,一個本身的服務器文件,一個目標服務器文件,用來咱們作請求使用;
在 a.html
中新建一個 iframe
,其 src
爲 http://localhost:4000/b.html
:
<!-- a.html -->
...
<body>
<h1>postmessage A 頁面</h1>
<iframe src="http://localhost:4000/b.html" id="frame" frameborder="10" onload="load()" ></iframe>
</body>
...
<!-- b.html -->
...
<body>
<h1>postmessage B 頁面</h1>
</body>
...
複製代碼
兩個 server
文件和 CORS
同樣,只不過都是開啓兩個簡單的服務而已。
我麼想要從 a
頁面發送一些信息給 b
頁面,同時 b
在收到消息後在回信給 a
頁面。
咱們能夠修改 a.html
,補充 iframe
的 load
函數,咱們在 a
頁面發送咱們定義好的信息給 b
頁面,同時監聽 b
頁面回發過來的信息,具體配置可參考 postMessge
官方文檔:
...
<script> function load() { let frame = document.getElementById("frame"); var iwindow = frame.contentWindow; // 發送 postMessage 信息 // 第一個:要傳的數據 // 第二個:指定源 iwindow.postMessage({ type: 'a', data: "我是 a 發的消息", }, "http://localhost:4000") } // 監聽 b 頁面發過來的信息 window.addEventListener('message', function(event){ // 拿到數據,判斷是否是從 b 發過來的 // 若是不是 直接 return const { type, data } = event.data; if (!event.data || type !== 'b') { return; } console.log(data); }) </script>
...
複製代碼
在 b
中監聽 a
發過來的信息:
...
<script> window.addEventListener('message', function(event){ console.log(event.data.data); event.source.postMessage({ type: 'b', data: "我是 b 發的消息", }, event.origin); }) </script>
...
複製代碼
咱們開啓兩個服務,在頁面中打開 localhost:3000/a.html
,能夠看到信息打印了出來:
不一樣域之間能夠經過 window.location.hash
進行傳遞相應的信息,在同域名直接能夠直接經過 js
訪問來設置:
咱們新建 hash
文件夾,並新建五個文件,三個 html
文件,兩個同源 html
,一個不一樣源 html
,兩個服務器文件,一個本身的服務器文件,一個目標服務器文件,用來咱們作請求使用,服務器文件和以前同樣,就不列舉了。
兩個同源 html
:a
和 b
文件,在 3000
端口下,另一個 c
在 4000
端口下:
<!-- a.html -->
...
<body>
<!-- 路徑後的 hash 能夠用來通訊 -->
<!-- a 訪問 c -->
<h1>window-hash a.html</h1>
<iframe src="http://localhost:4000/c.html#hashname=darrell" id="frame" frameborder="10" ></iframe>
</body>
...
<!-- b.html -->
...
<body>
<h1>window-hash b.html</h1>
</body>
...
<!-- c.html -->
...
<body>
<h1>window-hash c.html</h1>
</body>
...
複製代碼
完成 a
與 c
頁面的通訊過程,在 a.html
中的 iframe
向 c.html
發送 #hashname=darrell
,c
取到以後在發送相關的信息給 a
,a
在進行相應的處理。
其實很簡單,咱們在 c
獲得 a
發過來的信息以後在新建 iframe
指向一個和a
同源的 b
,做爲一箇中轉站,由於 a
和 b
同源,接着就能夠直接經過 js
訪問了,咱們修改一下 html
代碼:
<!-- a.html -->
...
<body>
<!-- 路徑後的 hash 能夠用來通訊 -->
<!-- a 訪問 c -->
<h1>window-hash a.html</h1>
<iframe src="http://localhost:4000/c.html#hashname=darrell" id="frame" frameborder="10" ></iframe>
<script> // 監聽 b 修改 hashchange window.onhashchange = function() { console.log('a 收到', location.hash); } </script>
</body>
...
<!-- b.html -->
...
<body>
<h1>window-hash b.html</h1>
<script> // 收到 c 發過來的 hash console.log('b 收到', location.hash); window.parent.parent.location.hash = window.location.hash; </script>
</body>
...
<!-- c.html -->
...
<body>
<h1>window-hash c.html</h1>
<script> // 收到 a 發過來的 hash console.log('c 收到', window.location.hash); let iframe = document.createElement('iframe'); iframe.src = 'http://localhost:3000/b.html#name=c'; document.body.appendChild(iframe); </script>
</body>
...
複製代碼
咱們開啓兩個服務,在頁面中打開 localhost:3000/a.html
,能夠看到信息打印了出來:
window.name
有一個特性,就是 name
值在不一樣的頁面(甚至不一樣域名)加載後依舊存在。所以咱們也可使用其幫助咱們解決跨域問題。
咱們新建 name
文件夾,並新建五個文件,代碼和 hash
的文件代碼同樣。
<!-- a.html -->
...
<body>
<h1>window-name a.html</h1>
<iframe src="http://localhost:4000/c.html#hashname=darrell" id="frame" frameborder="10" ></iframe>
</body>
...
<!-- b.html -->
...
<body>
<h1>window-name b.html</h1>
</body>
...
<!-- c.html -->
...
<body>
<h1>window-name c.html</h1>
<script> window.name = '我是來自 c 的信息'; </script>
</body>
...
複製代碼
需求也相似,我須要在 a
獲取到 c
這個頁面進行定義的 window.name
,其實很簡單咱們只要經過 b
這個中間頁面進行數據傳遞就好了,當咱們加載完成 c
頁面這個 iframe
之後,再從新將 src
賦值爲 http://localhost:3000/b.html
,利用 name
的特性,這個時候 a
頁面就能夠經過 window.name
拿到 c
中的 name
了,咱們只須要修改 a.html
文件就能夠了:
<!-- a.html -->
...
<body>
<h1>window-name a.html</h1>
<iframe src="http://localhost:4000/c.html" id="frame" frameborder="10" onload="load()" ></iframe>
<script> let first = true; function load() { let frame = document.getElementById("frame"); let iwindow = frame.contentWindow; if (first) { frame.src = 'http://localhost:3000/b.html'; first = false; } else { console.log(iwindow.name); } } </script>
</body>
...
複製代碼
咱們開啓兩個服務,在頁面中打開 localhost:3000/a.html
,能夠看到信息打印了出來:
在兩個域名是同一個主域的時候,若是須要進行跨域通訊,咱們能夠將兩個頁面都經過 js
強制設置document.domain
爲基礎主域,這就實現了同域。
咱們新建 domain
文件夾,並新建四個文件,兩個不一樣源的 html
,兩個服務文件和 name
相同:
咱們配置一下系統的 host
文件,將 127.0.0.1
配置出兩個虛擬域名:a.example.cn
、b.example.cn
:
這樣咱們就能使用 a.example.cn:3000/a.html
和 b.example.cn:4000/b.html
來訪問兩個 html
文件了,
由於兩個域名的主域相同,咱們能夠設置 document-domain=example.cn
來實現:
<!--a.html-->
...
<body>
<!-- 配置 host -->
<!-- http://a.example.cn:3000/a.html -->
<h1>document-domain a.html</h1>
<iframe src="http://b.example.cn:3000/b.html" id="frame" frameborder="10" onload="load()" ></iframe>
<script> document.domain = "example.cn"; function load() { let frame = document.getElementById("frame"); let iwindow = frame.contentWindow; console.log(iwindow.name); } </script>
</body>
...
<!--b.html-->
...
<body>
<h1>document-domain b.html</h1>
<script> document.domain = "example.cn"; var name = 'b 定義的 name'; </script>
</body>
...
複製代碼
咱們開啓兩個服務,在頁面中打開 http://a.example.cn/:3000/a.html
,能夠看到信息打印了出來:
須要注意的是此方案只能在主域相同,子域不一樣的跨域應用場景。其餘狀況下不能使用。
WebSocket
是 HTML5
一種新的協議。它實現了瀏覽器與服務器全雙工通訊,同時容許跨域通信。
咱們先用原生的 WebSocket
來舉個例子,以後再使用 Socket.io
來舉個例子:
WebSocket
咱們新建 websocket
文件夾,新建 socket.html
和 server.js
文件:
咱們建立一個 socket
實例,並向服務端發送一些消息,同時監聽服務端發送給客戶端的消息。
...
<body>
<h1>Socket demo</h1>
<script> let socket = new WebSocket("ws://localhost:3000"); socket.onopen = function() { socket.send('瀏覽器發出的內容'); } socket.onmessage = function(e) { console.log(e.data); } </script>
</body>
...
複製代碼
咱們安裝一個依賴 ws
,用來處理 websocket
,接着起一個 websocket
服務器,監聽客戶端的信息,同時發送相應的信息出到客戶端。
let express = require('express');
let WebSocket = require('ws');
let wss = new WebSocket.Server({ port: 3000 });
wss.on('connection', function(ws) {
ws.on('message', function(data) {
console.log(data);
ws.send('服務器發的內容');
})
})
複製代碼
咱們開啓一下服務,這個時候咱們能夠直接打開 file
協議的 socket.html
,咱們能夠在控制檯看到服務器發送過來的信息,同時也能夠在服務端開到客戶端發送過來的信息:
由於原生 WebSocket API
不是特別好用,兼容性也很差,咱們可使用 Socket.io
,它很好地封裝了 webSocket
接口,提供了更簡單、靈活的接口。同時對不支持 Websocket
的瀏覽器作了向下兼容。
咱們這個例子參考了官方的一個 簡易聊天室,同時咱們須要安裝一下 socket.io
:
npm install socket.io
複製代碼
<!-- 引入 socketIO.html -->
...
<body>
<ul id="messages"></ul>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</ul>
<!-- 引入 socket.io 和 jquery 的 cdn -->
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script> $(function () { //創建一個socket var socket = io(); $('form').submit(function(){ //發送socket到服務器。 socket.emit('chat message', $('#m').val()); $('#m').val(''); return false; }); socket.on('chat message', function(msg){ //接受服務器傳回來的數據,新建一個li標籤 $('#messages').append($('<li>').text(msg)); window.scrollTo(0, document.body.scrollHeight); }); }); </script>
</body>
...
複製代碼
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
var port = process.env.PORT || 3000;
app.get('/', function(req, res){
res.sendFile(__dirname + '/socketIO.html');
});
io.on('connection', function(socket){
// 監聽socket是否鏈接,若是鏈接的話,就發送數據,chat-message
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
// 監聽socket是否斷開,斷開時執行相應的方法
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
http.listen(port, function(){
console.log('listening on *:' + port);
});
複製代碼
咱們啓動一下服務:node ./websocket/serverIO.js
:咱們能夠在兩個頁面互發消息,以下圖:
若是你在你的項目中使用了 webpack
,那麼 webpack
的 devServer
中提供了相應的配置參數,你只要在其中進行配置便可:
module.exports = {
...
devServer: {
// 代理
proxy: {
'/movie/': {
target: 'https://douban.uieee.com/v2',
// 是否能夠容許跨域
changeOrigin: true,
headers: {
host:'www.example.org',
cookie: 'isLogin=1' // 判斷是否登陸的 cookie 信息
}
}
}
}
};
複製代碼
更多的關於 webpack
中 devServer
的配置,你們能夠參考筆者寫的 webpack-dev-server 高級配置,在這裏就不細講了。
文章參考了 前端常見跨域解決方案(全),同時加入了本身的思考和代碼示例,但願你們看完以後,能對跨域通訊的解決辦法瞭然於胸。