内容简介:系列文章:在系列文章的第一篇我们谈到过跨域问题产生的原因是ps: 本文涉及到部分后端知识, 需要有一丢丢的
系列文章:
- 【小哥哥, 跨域要不要了解下】JSONP
- 【小哥哥, 跨域要不要了解下】CORS 基础篇
- 【小哥哥, 跨域要不要了解下】CORS 进阶篇
- 【小哥哥, 跨域要不要了解下】NGINX 反向代理
- 【小哥哥, 跨域要不要了解下】ServerProxy
在系列文章的第一篇我们谈到过跨域问题产生的原因是 浏览器 的同源策略. 那么服务器之间通信就不会受到相关条件的限制. 那么是不是我们可以通过同域服务器帮助访问其他域名的 api 呢? 如果可以的话, 那岂不是可以想访问谁就访问谁? 限制, 不存在的...
ps: 本文涉及到部分后端知识, 需要有一丢丢的 nodejs
koa
基础. 主要用于搭建一个 web
服务器, 当然没有基础也没啥关系, 先去node koa 官网看看. 回不回来???
随你咯 :smile:
创建项目目录
继续上一步, 本文只会创建一个后端项目. 所以不需要在 ./fe
目录下创建前端项目啦, 项目目录如下.
其中, serverProxy
目录是项目的主目录. www
目录即为前端静态文件的托管目录. base.js
为后端主程序, add.js subtract.js
分别表示两个第三方服务, 分别提供了计算加法和减法的能力.
安装 koa
- 首先执行
cd be/serverProxy
将路径切换到serverProxy
- 执行
npm init -y
初始化为一个 node 项目 - 执行
npm i koa -S
完成koa
的安装
验证 koa
安装是否完成
- 编辑
base.js
写入以下内容
const Koa = require('koa'); const app = new Koa(); const PORT = 1234; app.use((ctx) => { ctx.body = 'Hello World'; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
- 完成后执行
node base.js
看到命令行中输出了the server is listen: 1234
说明启动成功 - 浏览器访问localhost
此时 代码
引入 koa-static
模块
在之前文章中, 我们总是要通过 live-server
启动一个本地的静态资源服务. 用于托管前端静态文件. koa
生态中有现成的中间件 koa-static
可以提供直接在后端项目中创建静态资源服务的能力.
- 首先执行
npm i koa-static -S
安装koa-static
- 调整
base.js
const Koa = require('koa'); // 引入 koa-static const koaStatic = require('koa-static'); const app = new Koa(); const PORT = 1234; // 使用 koa-static 中间件, 并指定静态文件目录为 www app.use(koaStatic('./www')); app.use((ctx) => { console.log(ctx.req.url); ctx.body = 'Hello World'; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
- 编写前端
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>ServerProxy 实现跨域</title> </head> <body> ServerProxy 实现跨域 </body> </html> 复制代码
- 执行
node base.js
重启项目 - 浏览器打开 localhost:1234/index.html
之前准备的 html 页面赫然在目 :smile:. 至此, 静态文件服务就搭建成功了(相当于我们自己实现了一个 live-server
) 代码地址
通过 ajax 访问当前后端接口
通过 koa-static
中间件, 我们搭建了一个自己的静态文件服务器. 接下来演示一个不跨域的请求...
- 首先修改后端代码
const Koa = require('koa'); const koaStatic = require('koa-static'); const app = new Koa(); const PORT = 1234; app.use(koaStatic('./www')); app.use((ctx) => { let ret; // 获取本次接收的请求的请求路径 const path = ctx.req.url; // 如果请求路径以api开头, 那么作为接口请求处理 if (path.startsWith('/api')) { // 这样实现的路由不是很优雅, 但是能用 :joy: switch (path) { case '/api/getFriend': ret = { name: 'quanquan', friend: 'gl' }; break; default: ret = { errno: 1, errmsg: '未知接口' }; break; } } ctx.body = ret; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
上述代码中定义了 /api/getFriend
接口, 通过浏览器访问的如下图:
node base.js
重启后端项目
接下来修改前端代码. 通过 ajax 的方式访问该接口
修改前端代码:
<!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>ServerProxy 实现跨域</title> </head> <body> ServerProxy 实现跨域 <script> // 一个常规的 ajax, 感兴趣的兄弟们也看看. 手写 ajax 好多面试官还在考 var xhr = new XMLHttpRequest() xhr.open('GET', '/api/getFriend') xhr.onreadystatechange = function() { if(xhr.readyState === 4 && xhr.status === 200) { console.log('接口返回的数据为: ', xhr.responseText) } } xhr.send() </script> </body> </html> 复制代码
刷新浏览器, 控制台展示如下. 没有报错, 返回的信息前端直接拿到了.
原来前后端同域时数据交互这么的简单.
前后端跑通阶段 代码
完善第三方服务
项目开发中经常会用到一些基础服务, 比如天气信息, 地理位置信息等等. 这些服务能力一般是通过调用第三方的接口来实现的(你开发一个网站, 先发射一颗气象卫星到天上也不太现实). 这一步我们创建两个第三方服务, 分别提供加法和减法运算.
加法运算服务 add.js
const Koa = require('koa'); const app = new Koa(); const PORT = 1111; app.use((ctx) => { // 获取参数 const { a, b } = ctx.query; // 尝试将参数转化为数字后进行加法操作 const result = Number(a) + Number(b); ctx.body = { result }; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
执行命令 node add.js
启动程序, 然后浏览器端访问localhost得到的结果如下, 说明加法计算服务启动成功.
减法运算服务 subtract.js
const Koa = require('koa'); const app = new Koa(); const PORT = 2222; app.use((ctx) => { // 获取参数 const { a, b } = ctx.query; // 尝试将参数转化为数字后进行减法操作 const result = Number(a) - Number(b); ctx.body = { result }; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
执行命令 node subtract.js
启动程序, 然后浏览器端访问localhost得到的结果如下, 说明减法计算服务启动成功.
目前 代码
通过后端代理访问第三方服务
创建完加法和减法服务, 我们还是有侥幸心理忍不住在前端项目里访问一下试试, 万一能通了呢? 就不用费事儿研究跨域了, 尝试一下
修改前端代码中的接口地址 xhr.open('GET', 'http://localhost:1111/?a=1&b=2')
完整代码 , 之后直接刷新浏览器(请思考, 为什么修改了 js 文件需要执行 node ...
重启服务, 而修改了 html 文件只需要刷新浏览器就可以了呢?).
还是之前的报错, 还是熟悉的味道. 不好使...
回想一下之前的思路. 浏览器有同源策略的限制服务器没有. 我们的前端项目托管在后端项目中所以访问我们自己的后端不跨域. 我们的后端请求第三方服务没有限制. 那么 ^_^
npm i axios -S
base.js
const Koa = require('koa'); const koaStatic = require('koa-static'); const axios = require('axios'); const app = new Koa(); const PORT = 1234; app.use(koaStatic('./www')); app.use(async (ctx) => { let ret; // 获取本次接收的请求的请求路径 const path = ctx.req.url.split('?')[0]; console.log('ctx.query.server', ctx.query.server); // 如果请求路径以api开头, 那么作为接口请求处理 if (path.startsWith('/api')) { // 这样实现的路由不是很优雅, 但是能用 :joy: switch (path) { case '/api/getFriend': ret = { name: 'quanquan', friend: 'gl' }; break; // 如果接口需要代理接口路径为 /api/proxy case '/api/proxy': // axios 直接访问前端给出的目标服务器url, 并将目标服务器返回的数据直接返回给前端 ret = (await axios.get(ctx.query.server)).data; break; default: ret = { errno: 1, errmsg: '未知接口' }; break; } } ctx.body = ret; }); app.listen(PORT, () => { console.log('the server is listen: ', PORT); }); 复制代码
前端代码:
<!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>ServerProxy 实现跨域</title> </head> <body> <h3>ServerProxy 实现跨域</h3> a: <input type="text" id="a" value="1"> b: <input type="text" id="b" value="2"> <button id="add">计算加法</button> <button id="subtrnct">计算减法</button> <div>计算结果为: <span id="ret"></span></div> <script> var aDom = document.getElementById('a') var bDom = document.getElementById('b') var addBtn = document.getElementById('add') var subtrnctDom = document.getElementById('subtrnct') var retDom = document.getElementById('ret') function add() { if(!a.value.trim() || !b.value.trim()) return var xhr = new XMLHttpRequest() xhr.open('GET', '/api/proxy' + '?server=' + encodeURIComponent('http://localhost:1111/?a='+ a.value +'&b=' + b.value)) xhr.onreadystatechange = function() { if(xhr.readyState === 4 && xhr.status === 200) { console.log('接口返回的数据为: ', xhr.responseText) retDom.innerHTML = JSON.parse(xhr.responseText).result } } xhr.send() } function subtrnct() { if(!a.value.trim() || !b.value.trim()) return var xhr = new XMLHttpRequest() xhr.open('GET', '/api/proxy' + '?server=' + encodeURIComponent('http://localhost:2222/?a='+ a.value +'&b=' + b.value)) xhr.onreadystatechange = function() { if(xhr.readyState === 4 && xhr.status === 200) { console.log('接口返回的数据为: ', xhr.responseText) retDom.innerHTML = JSON.parse(xhr.responseText).result } } xhr.send() } addBtn.addEventListener('click', add) subtrnctDom.addEventListener('click', subtrnct) </script> </body> </html> 复制代码
最后结果:
结语: ServerProxy 的原理大概就是这个样子的啦, 通过 ajax 访问同域后端服务, 后端服务访问目标服务并将目标服务返回的内容透传给前端. 当然实际操作起来不会像例子这么简单. 我的另一个系列文章 【手把手带你撸一个接口测试工具】 将会详细介绍复杂一些的情况, 包括不同的请求类型, 请求头设置以及响应头获取等等. 希望感兴趣的小伙伴继续关注.
关于跨域的其他方式:document.domain 一行代码可以搞定, 适合同主域名不同子域名的情况.postMessage 需要添加额外 iframe, 整体实现较为简单, 一个 API 搞定, 感兴趣的同学可以看看文档. 还有一些比较小众的做法 flash
CSST
前端打点尝尝用到的 img 标签等等, 这里就不一一列举了, 学无止境...
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 【小哥哥, 跨域要不要了解下】JSONP
- 【小哥哥, 跨域要不要了解下】NGINX 反向代理
- 三种缓存方式,再也不用麻烦运维小哥哥了!!!
- 小哥哥~手把手教你如何绘制一辆跑车
- Windows Phone开发之怪现象 - msp的昌伟哥哥
- Windows Phone开发之怪现象 - msp的昌伟哥哥
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。