【小哥哥, 跨域要不要了解下】ServerProxy

栏目: Node.js · 发布时间: 5年前

内容简介:系列文章:在系列文章的第一篇我们谈到过跨域问题产生的原因是ps: 本文涉及到部分后端知识, 需要有一丢丢的

系列文章:

在系列文章的第一篇我们谈到过跨域问题产生的原因是 浏览器 的同源策略. 那么服务器之间通信就不会受到相关条件的限制. 那么是不是我们可以通过同域服务器帮助访问其他域名的 api 呢? 如果可以的话, 那岂不是可以想访问谁就访问谁? 限制, 不存在的...

【小哥哥, 跨域要不要了解下】ServerProxy

ps: 本文涉及到部分后端知识, 需要有一丢丢的 nodejs koa 基础. 主要用于搭建一个 web 服务器, 当然没有基础也没啥关系, 先去node koa 官网看看. 回不回来???

随你咯 :smile:

创建项目目录

继续上一步, 本文只会创建一个后端项目. 所以不需要在 ./fe 目录下创建前端项目啦, 项目目录如下.

【小哥哥, 跨域要不要了解下】ServerProxy

其中, 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
【小哥哥, 跨域要不要了解下】ServerProxy

此时 代码

引入 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>
复制代码
【小哥哥, 跨域要不要了解下】ServerProxy

之前准备的 html 页面赫然在目 :smile:. 至此, 静态文件服务就搭建成功了(相当于我们自己实现了一个 live-server ) 代码地址

通过 ajax 访问当前后端接口

通过 koa-static 中间件, 我们搭建了一个自己的静态文件服务器. 接下来演示一个不跨域的请求...

【小哥哥, 跨域要不要了解下】ServerProxy
  • 首先修改后端代码
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 接口, 通过浏览器访问的如下图:

【小哥哥, 跨域要不要了解下】ServerProxy
ps: 需要执行 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>
复制代码

刷新浏览器, 控制台展示如下. 没有报错, 返回的信息前端直接拿到了.

【小哥哥, 跨域要不要了解下】ServerProxy

原来前后端同域时数据交互这么的简单.

【小哥哥, 跨域要不要了解下】ServerProxy

前后端跑通阶段 代码

完善第三方服务

项目开发中经常会用到一些基础服务, 比如天气信息, 地理位置信息等等. 这些服务能力一般是通过调用第三方的接口来实现的(你开发一个网站, 先发射一颗气象卫星到天上也不太现实). 这一步我们创建两个第三方服务, 分别提供加法和减法运算.

加法运算服务 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得到的结果如下, 说明加法计算服务启动成功.

【小哥哥, 跨域要不要了解下】ServerProxy

减法运算服务 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得到的结果如下, 说明减法计算服务启动成功.

【小哥哥, 跨域要不要了解下】ServerProxy

目前 代码

通过后端代理访问第三方服务

创建完加法和减法服务, 我们还是有侥幸心理忍不住在前端项目里访问一下试试, 万一能通了呢? 就不用费事儿研究跨域了, 尝试一下

【小哥哥, 跨域要不要了解下】ServerProxy

修改前端代码中的接口地址 xhr.open('GET', 'http://localhost:1111/?a=1&b=2') 完整代码 , 之后直接刷新浏览器(请思考, 为什么修改了 js 文件需要执行 node ... 重启服务, 而修改了 html 文件只需要刷新浏览器就可以了呢?).

【小哥哥, 跨域要不要了解下】ServerProxy

还是之前的报错, 还是熟悉的味道. 不好使...

回想一下之前的思路. 浏览器有同源策略的限制服务器没有. 我们的前端项目托管在后端项目中所以访问我们自己的后端不跨域. 我们的后端请求第三方服务没有限制. 那么 ^_^

【小哥哥, 跨域要不要了解下】ServerProxy
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

结语: ServerProxy 的原理大概就是这个样子的啦, 通过 ajax 访问同域后端服务, 后端服务访问目标服务并将目标服务返回的内容透传给前端. 当然实际操作起来不会像例子这么简单. 我的另一个系列文章 【手把手带你撸一个接口测试工具】 将会详细介绍复杂一些的情况, 包括不同的请求类型, 请求头设置以及响应头获取等等. 希望感兴趣的小伙伴继续关注.

关于跨域的其他方式:document.domain 一行代码可以搞定, 适合同主域名不同子域名的情况.postMessage 需要添加额外 iframe, 整体实现较为简单, 一个 API 搞定, 感兴趣的同学可以看看文档. 还有一些比较小众的做法 flash CSST 前端打点尝尝用到的 img 标签等等, 这里就不一一列举了, 学无止境...

【小哥哥, 跨域要不要了解下】ServerProxy

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

图解CSS3

图解CSS3

廖伟华 / 机械工业出版社 / 2014-7-1 / CNY 79.00

本书是CSS3领域的标准性著作,由资深Web前端工程师根据CSS3的最新技术标准撰写。内容极为全面、丰富和翔实,由浅入深地讲解了CSS3新特性的语法、功能和使用技巧,涵盖选择器、边框、背景、文本、颜色、UI、动画、新型盒模型、媒体查询、响应式设计等各种模块;写作方式创新,有趣且易懂,用图解的方式来描述CSS3的每一个特性甚至每一个步骤都配有实战效果图;包含大量案例,实战性强,每个特性都有作者从实践......一起来看看 《图解CSS3》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试