Node 代理访问的实现


Posted in Javascript onSeptember 19, 2019

NODE代理访问

1. 场景

  • 本地开发,代理访问,防止跨域(一般通过webpack配置代理即可),特殊情况如携带一些自定义的登录cookie则需要通过自己写node
  • 作为一种server中间层,单线程异步可以缓解服务器压力。长链接websocket通常使用node搭建

2. 技术框架

  • node - koa2 体量小,轻便易用。
  • 路由koa-router koa配套路由,中间件支持async
  • koa2-request 基于async对 request的封装,这里本人git上找的,可靠性带考量,若基于生产环境建议使用request自行封装
  • koa-bodyparser 请求参数解析格式化-中间件

3. 上代码

3.1 创建应用 app.js

const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
// 路由
const router = require('./router')
const app = new Koa()

app.use(
 bodyParser({
   // 返回的对象是一个键值对,当extended为false的时候,键值对中的值就为'String'或'Array'形式,为true的时候,则可为任何数据类型。
  extended: true 
 })
)

3.2 允许跨域 app.js

app.use(async (ctx, next) => {
 ctx.set('Access-Control-Allow-Origin', '*')
 ctx.set('Access-Control-Allow-Headers', 'content-type')
 ctx.set(
  'Access-Control-Allow-Methods',
  'OPTIONS,GET,HEAD,PUT,POST,DELETE,PATCH'
 )
 await next()
})

3.2 使用路由

// app.js

app.use(router.routes())


// router.js

const Router = require('koa-router')
let koaRequest = require('./httpRequest')
const router = new Router()

router.get('/*', async (ctx, next) => {
 const url = setQuestUrl(ctx.url)
 try {
  let res = await koaRequest(url, 'GET', ctx)
  ctx.body = res
 } catch (err) {
  ctx.body = err
 }
})

router.post('/*', async (ctx, next) => {
 const url = setQuestUrl(ctx.url)
 try {
  let res = await koaRequest(url, 'POST', ctx)
  ctx.body = res
 } catch (err) {
  ctx.body = err
 }
})

function setQuestUrl(url) {
 if (/^\/t/.test(url)) {
  return 'host1'+ url.replace(/^\/t/, '')
 }
 if (/^\/xt/.test(url)) {
  return 'host2' + url.replace(/^\/xt/, '')
 }
}

module.exports = router
  • router.get('/*', async (ctx, next) => {}) koa路由 ‘/*' 为通配符,匹配所有get请求;next方法调用表示进入下一个中间件;
  • ctx请求上下文,ctx.request.body post请求参数
  • koa的中间件原理 洋葱圈模型:

Node 代理访问的实现

const Koa = require('koa2');
const app = new Koa();

// logger
app.use(async (ctx, next) => {
 console.log('第一层洋葱 - 开始')
 await next();
 const rt = ctx.response.get('X-Response-Time');
 console.log(`${ctx.method} ${ctx.url} - ${rt}`);
 console.log('第一层洋葱 - 结束')
});

// x-response-time
app.use(async (ctx, next) => {
 console.log('第二层洋葱 - 开始')
 const start = Date.now();
 await next();
 const ms = Date.now() - start;
 ctx.set('X-Response-Time', `${ms}ms`);
 console.log('第二层洋葱 - 结束')
});

// response
app.use(async ctx => {
 console.log('第三层洋葱 - 开始')
 ctx.body = 'Hello World';
 console.log('第三层洋葱 - 结束')
});

app.listen(8000);


// 输出

第一层洋葱 - 开始
第二层洋葱 - 开始
第三层洋葱 - 开始

第三层洋葱 - 结束
第二层洋葱 - 结束
第一层洋葱 - 结束

setQuestUrl 此方法主要是将前端访问的路径,根据第一级转发到不同的host上

例如: /t -> host1

3.3 转发请求 httpRequest.js

本例主要为了代理访问并携带Cookie, const.js 为写死的要携带的cookie

let koa2Req = require('koa2-request')

let constConfig = require('./const')

let iToken = constConfig.iToken

let koaRequest = async function(url, method, ctx) {
 let options = {
  method: method,
  uri: url,
  timeout: 120000,
  body: ctx
   ? {
     ...ctx.request.body
    }
   : null,
  headers: {},
  json: true // Automatically stringifies the body to JSON
 }
 options.headers['Cookie'] = `i-token=${iToken}` //设置cookie
 let res = await koa2Req(options)

 return res.body
}

// node-mon

async function getTestToken() {
 if (!constConfig.iToken) {
  let url = `http://xt.eqxiu.com/tui/app/radar/test/getToken?companyId=${constConfig.companyId}&staffId=${constConfig.staffId}`
  try {
   let res = await koaRequest(url, 'GET')
   iToken = res.obj
   console.log('token已拿到:' + iToken)
  } catch (e) {
   console.log(e)
  }
 }
}

getTestToken()

module.exports = koaRequest

3.4 最后设置端口等

const app = require('./app')
//const createWebsocket = require('./websocket')

const server = require('http').createServer(app.callback())

server.setTimeout(2 * 60 * 1000) //设置超时时间

const { PORT = 3000 } = process.env

server.listen(PORT, () => {
 console.log(`Listening on port ${PORT}`)
})

3.5 本地开发,热重启

安装 nodemon

yarn add nodemon

设置忽略监听

nodemon.josn node项目根目录下

{
 "ignore": ["node_modules/*"] //忽略node_modules下文件修改的监听
}

package.josn

通过npm run server启动

{
 "dependencies": {
  "koa": "^2.8.1",
  "koa-bodyparser": "^4.2.1",
  "koa-router": "^7.4.0",
  "koa2-request": "^1.0.4",
  "nodemon": "^1.19.1"
 },
 "scripts": {
  "server": "nodemon index.js"
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
实现超用户体验 table排序javascript实现代码
Jun 22 Javascript
JQuery 插件制作实践 xMarquee插件V1.0
Apr 02 Javascript
jQuery 验证插件 Web前端设计模式(asp.net)
Oct 17 Javascript
JQuery的AJAX实现文件下载的小例子
May 15 Javascript
jQuery提交多个表单的小例子
Jun 30 Javascript
javascript 实现 原路返回
Jan 21 Javascript
深入php面向对象、模式与实践
Feb 16 Javascript
js替换字符串中所有指定的字符(实现代码)
Aug 17 Javascript
基于node搭建服务器,写接口,调接口,跨域的实例
May 13 Javascript
jQuery实现经典的网页3D轮播图封装功能【附源码下载】
Feb 15 jQuery
详解jQuery如何实现模糊搜索
May 10 jQuery
javascript实现抢购倒计时程序
Aug 26 Javascript
浅谈laytpl 模板空值显示null的解决方法及简单的js表达式
Sep 19 #Javascript
微信小程序进入广告实现代码实例
Sep 19 #Javascript
解决layui数据表格Date日期格式的回显Object的问题
Sep 19 #Javascript
转换layUI的数据表格中的日期格式方法
Sep 19 #Javascript
js 判断当前时间是否处于某个一个时间段内
Sep 19 #Javascript
vue-froala-wysiwyg 富文本编辑器功能
Sep 19 #Javascript
关于layui toolbar和template的结合使用方法
Sep 19 #Javascript
You might like
PHP教程之PHP中shell脚本的使用方法分享
2012/02/23 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
2014/08/11 PHP
php修改指定文件后缀的方法
2014/09/11 PHP
php针对cookie操作的队列操作类实例
2014/12/10 PHP
深入理解PHP 数组之count 函数
2016/06/13 PHP
php设计模式之代理模式分析【星际争霸游戏案例】
2020/03/23 PHP
TP5框架实现上传多张图片的方法分析
2020/03/29 PHP
理解 JavaScript 预解析
2009/10/25 Javascript
JQuery 学习笔记01 JQuery初接触
2010/05/06 Javascript
jquery如何根据值设置默认的选中项
2014/03/17 Javascript
JavaScript 动态加载脚本和样式的方法
2015/04/13 Javascript
js验证上传图片的方法
2015/05/12 Javascript
jQuery实现的瀑布流加载效果示例
2016/09/13 Javascript
基于BootStrap栅格栏系统完成网站底部版权信息区
2016/12/23 Javascript
vue中如何创建多个ueditor实例教程
2017/11/14 Javascript
JS伪继承prototype实现方法示例
2018/06/20 Javascript
JS实现的字符串数组去重功能小结
2019/06/17 Javascript
JS制作简易计算器的实例代码
2020/07/04 Javascript
[01:15:00]LGD vs Mineski Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
python单例模式实例分析
2015/04/08 Python
Python类属性的延迟计算
2016/10/22 Python
python 字符串转列表 list 出现\ufeff的解决方法
2017/06/22 Python
django开发教程之利用缓存文件进行页面缓存的方法
2017/11/10 Python
Django 根据数据模型models创建数据表的实例
2018/05/27 Python
Python使用__new__()方法为对象分配内存及返回对象的引用示例
2019/09/20 Python
Python 列表的清空方式
2020/01/13 Python
PYQT5 vscode联合操作qtdesigner的方法
2020/03/24 Python
CSS3 clip-path 用法介绍详解
2018/03/01 HTML / CSS
小学生环保演讲稿
2014/04/25 职场文书
暑期社会实践证明书
2014/11/17 职场文书
岁月神偷观后感
2015/06/11 职场文书
2015年医院保卫科工作总结
2015/07/23 职场文书
职工趣味运动会开幕词
2016/03/04 职场文书
redis客户端实现高可用读写分离的方式详解
2021/07/04 Redis
Win11安装受阻怎么办? Windows11安装问题与解决方案汇总
2021/11/21 数码科技
Java 死锁解决方案
2022/05/11 Java/Android