前端初学者都应该知道得跨域通讯方式

跨域是一个咱们常常遇到的问题,特别是当服务有两个域名的时候,若是你的页面是在 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:跨域资源共享
  • postMessageHTML5 提供的 api
  • Hash:不一样源能够访问 hash
  • window.name:不一样的页面(甚至不一样域名)加载后依旧存在
  • document.domain:主域相同的状况
  • websocketHTML5 提供的新的协议
  • webpack:等构建构建工具中提供的跨域解决办法
  • nginx:这个属于后端的,笔者在本文就不作详细介绍了,你们能够自行找相关资料,其实也蛮简单的

接下来咱们来详细讲一下这几种解决跨域问题的通讯方式,全部代码都会放在这个仓库中:跨域通讯 示例代码

JSONP

一般为了减轻 web 服务器的负载,咱们把 jscssimg 等静态资源分离到另外一台独立域名的服务器上,在html 页面中再经过相应的标签从不一样域名下加载静态资源,而被浏览器容许。

基于此原理,咱们能够经过动态建立 script,再请求一个带参网址实现跨域通讯。

案例代码

咱们新建 jsonp 文件夹,并新建三个文件

  • jsonp.js:封装了一个简易的 jsonp 方法,jsonp 其实就是新建一个 script 文件,由于咱们上面也讲到了 script 是不会跨域的,接着将须要请求的连接放在 scriptsrc 中,同时在 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);
  })
}
复制代码
  • server.js:起一个服务,咱们使用 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端口启动');
});
复制代码
  • index.html: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 中已经帮咱们封装好了,直接使用便可,但须要先引入 jquery,可使用 $.ajax 规定 dataType,具体笔者也不演示了,使用以下:

// ...
$.ajax({
  url: 'http://localhost:3000/jsonp',
  type: 'get',
  dataType: 'jsonp',  // 请求方式为jsonp
  success:function(ret){
    console.log(ret);
  }
});

复制代码

一些说明

使用起来很简单,兼容性好,能兼容一些远古浏览器。可是他只支持 GET 请求,同时会有安全的问题,可能会被 xss 注入。

 

CORS

CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它容许浏览器向跨源发送 XMLHttpRequest,主要在后端服务器中增长一些相关配置便可,但有的时候须要前端进行一些配合,接下来我会讲几个经常使用的配置:

案例代码

咱们新建 cors 文件夹,并新建四个文件,一个 html 文件,两个服务器文件,一个本身的服务器文件,一个目标服务器文件,用来咱们作请求使用;一个简单封装的 ajax.js 文件:

  • 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 文件
server1.js

这个文件和 jsonpserver.js 同样,在 3000 端口开启一个服务器,让咱们的 index.html 可以在 localhost:3000/index.html 访问。

server2.js

这个文件是目标服务器文件,端口号 4000,用来咱们发送 ajax 请求,这里咱们增长了一个 getData 方法:

// ...
app.get('/getData', function(req, res) {
  const data = {
    data: '我是 cors 的 data',
  }

  res.end(JSON.stringify(data));  
})
// ...
复制代码
  • index.html

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 了。

配置 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,咱们就能拿到相应的值了:

更多配置

咱们再来介绍几个经常使用的配置:

Access-Control-Allow-Headers

若是用户想要在头部设置一些值,则在后端须要定义这个头,它也是一个逗号分隔的字符串,代表服务器支持的全部头信息字段。若是不定义会报以下错误:

若是咱们想要在 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');
  }
  // ...
});
复制代码
Access-Control-Allow-Methods

它的值是逗号分隔的一个字符串,代表服务器支持的全部跨域请求的方法。若是个人请求方法为 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");
  }
  // ...
});
复制代码
Access-Control-Allow-Credentials

它的值是一个布尔值,表示是否容许发送 Cookie。默认状况下,Cookie 不包括在 CORS 请求之中。设为 true,即表示服务器明确许可,Cookie 能够包含在请求中,一块儿发给服务器。

若是在浏览器端设置了容许携带 cookiexhr.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);
  }
  // ...
});
复制代码
Access-Control-Expose-Headers

CORS 请求时,XMLHttpRequest对象的 getResponseHeader() 方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。若是想拿到其余字段,就必须在 Access-Control-Expose-Headers 里面指定。

好比我要在 ajaxresponse 中取返回头中的 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');
  }
  // ...
});
复制代码
Access-Control-Max-Age

用来指定本次预检请求的有效期,单位为秒。预检请求指的是浏览器针对于复杂请求的时候,会在正式通讯以前,增长一次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

postMessageHTML5 中的API,且是为数很少能够跨域操做的 window 属性之一,它可用于解决如下方面的问题

  • 页面和其打开的新窗口的数据传递,能够经过 opener 来进行通行。
  • 多窗口之间消息传递
  • 页面与嵌套的 iframe 消息传递
  • 上面三个场景的跨域数据传递

这里咱们就来举一个 iframe 嵌套的例子:

案例代码

咱们新建 postmessage 文件夹,并新建四个文件,两个不一样源 html 文件,两个服务器文件,一个本身的服务器文件,一个目标服务器文件,用来咱们作请求使用;

  • 两个 html

a.html 中新建一个 iframe,其 srchttp://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 文件

两个 server 文件和 CORS 同样,只不过都是开启两个简单的服务而已。

需求

我么想要从 a 页面发送一些信息给 b 页面,同时 b 在收到消息后在回信给 a 页面。

咱们能够修改 a.html,补充 iframeload 函数,咱们在 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,能够看到信息打印了出来:

 

Hash

不一样域之间能够经过 window.location.hash 进行传递相应的信息,在同域名直接能够直接经过 js 访问来设置:

案例代码

咱们新建 hash 文件夹,并新建五个文件,三个 html 文件,两个同源 html,一个不一样源 html,两个服务器文件,一个本身的服务器文件,一个目标服务器文件,用来咱们作请求使用,服务器文件和以前同样,就不列举了。

  • 三个 html 文件

两个同源 htmlab 文件,在 3000 端口下,另一个 c4000 端口下:

<!-- 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>
...
复制代码

需求:

完成 ac 页面的通讯过程,在 a.html 中的 iframec.html 发送 #hashname=darrellc 取到以后在发送相关的信息给 aa 在进行相应的处理。

其实很简单,咱们在 c 获得 a 发过来的信息以后在新建 iframe 指向一个和a 同源的 b,做为一个中转站,由于 ab 同源,接着就能够直接经过 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

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,能够看到信息打印了出来:

 

document.domain

在两个域名是同一个主域的时候,若是须要进行跨域通讯,咱们能够将两个页面都经过 js 强制设置document.domain 为基础主域,这就实现了同域。

案例代码

咱们新建 domain 文件夹,并新建四个文件,两个不一样源的 html,两个服务文件和 name 相同:

咱们配置一下系统的 host 文件,将 127.0.0.1 配置出两个虚拟域名:a.example.cnb.example.cn

这样咱们就能使用 a.example.cn:3000/a.htmlb.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

WebSocketHTML5 一种新的协议。它实现了浏览器与服务器全双工通讯,同时容许跨域通信。

咱们先用原生的 WebSocket来举个例子,以后再使用 Socket.io 来举个例子:

原生 WebSocket

咱们新建 websocket 文件夹,新建 socket.htmlserver.js 文件:

  • socket.html

咱们建立一个 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>
...
复制代码
  • server.js

咱们安装一个依赖 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,咱们能够在控制台看到服务器发送过来的信息,同时也能够在服务端开到客户端发送过来的信息:

 

sockit.io

由于原生 WebSocket API 不是特别好用,兼容性也很差,咱们可使用 Socket.io,它很好地封装了 webSocket 接口,提供了更简单、灵活的接口。同时对不支持 Websocket 的浏览器作了向下兼容。

咱们这个例子参考了官方的一个 简易聊天室,同时咱们须要安装一下 socket.io

npm install socket.io
复制代码
html 代码
<!-- 引入 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>
...
复制代码
serverIO.js
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 中的 devServer

若是你在你的项目中使用了 webpack,那么 webpackdevServer 中提供了相应的配置参数,你只要在其中进行配置便可:

module.exports = {
  ...
  devServer: {
    // 代理
    proxy: {
      '/movie/': {
      	target: 'https://douban.uieee.com/v2',
        // 是否能够容许跨域
      	changeOrigin: true,
      	headers: {
          host:'www.example.org',
          cookie: 'isLogin=1' // 判断是否登陆的 cookie 信息
        }
      }
    }
  }
};
复制代码

更多的关于 webpackdevServer 的配置,你们能够参考笔者写的 webpack-dev-server 高级配置,在这里就不细讲了。

 

一些说明

文章参考了 前端常见跨域解决方案(全),同时加入了本身的思考和代码示例,但愿你们看完以后,能对跨域通讯的解决办法了然于胸。

 

相关资料

 

示例代码

相关文章
相关标签/搜索