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 相关文章推荐
实例分析js和C#中使用正则表达式匹配a标签
Nov 26 Javascript
JavaScript中的eval()函数使用介绍
Dec 31 Javascript
Grunt入门教程(自动任务运行器)
Aug 06 Javascript
jquery 属性选择器(匹配具有指定属性的元素)
Sep 06 Javascript
js实现点击按钮弹出上传文件的窗口
Dec 23 Javascript
js+html获取系统当前时间
Nov 10 Javascript
Bootstrap 实现表格样式、表单布局的实例代码
Dec 09 Javascript
vue element upload实现图片本地预览
Aug 20 Javascript
微信小程序swiper组件实现抖音翻页切换视频功能的实例代码
Jun 24 Javascript
vue项目使用$router.go(-1)返回时刷新原来的界面操作
Jul 26 Javascript
vue 解决无法对未定义的值,空值或基元值设置反应属性报错问题
Jul 31 Javascript
详解vue修改elementUI的分页组件视图没更新问题
Nov 13 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
一个显示天气预报的程序
2006/10/09 PHP
PHP 引用是个坏习惯
2010/03/12 PHP
PHP编程实现微信企业向用户付款的方法示例
2017/07/26 PHP
Laravel中日期时间处理包Carbon的简单使用
2017/09/21 PHP
JavaScript 学习笔记(六)
2009/12/31 Javascript
jQuery EasyUI 中文API Layout(Tabs)
2010/04/27 Javascript
JQuery与JSon实现的无刷新分页代码
2011/09/13 Javascript
javascript中的注释使用与注意事项小结
2011/09/20 Javascript
修改js Calendar日历控件 兼容IE9/谷歌/火狐
2013/01/04 Javascript
JS方法调用括号的问题探讨
2014/01/24 Javascript
javascript中apply和call方法的作用及区别说明
2014/02/14 Javascript
js获取checkbox值的方法
2015/01/28 Javascript
javascript基于DOM实现省市级联下拉框的方法
2015/05/14 Javascript
NodeJs测试框架Mocha的安装与使用
2017/03/28 NodeJs
解决AjaxFileupload 上传时会出现连接重置的问题
2017/07/07 Javascript
Vuejs开发环境搭建及热更新【推荐】
2018/09/07 Javascript
node.js连接mysql与基本用法示例
2019/01/05 Javascript
JS组件库AlloyTouch实现图片轮播过程解析
2020/05/29 Javascript
[46:20]DOTA2-DPC中国联赛 正赛 PSG.LGD vs LBZS BO3 第二场 1月22日
2021/03/11 DOTA
python实现通过shelve修改对象实例
2014/09/26 Python
Python多进程同步简单实现代码
2016/04/27 Python
Python中对数组集进行按行打乱shuffle的方法
2018/11/08 Python
将string类型的数据类型转换为spark rdd时报错的解决方法
2019/02/18 Python
Python实现KNN(K-近邻)算法的示例代码
2019/03/05 Python
Django框架组成结构、基本概念与文件功能分析
2019/07/30 Python
基于tensorflow指定GPU运行及GPU资源分配的几种方式小结
2020/02/03 Python
Python爬虫后获取重定向url的两种方法
2021/01/19 Python
在HTML5中如何使用CSS建立不可选的文字
2014/10/17 HTML / CSS
Speedo速比涛法国官方网站:泳衣、泳镜、泳帽、泳裤
2019/07/30 全球购物
美国工业用品采购网站:Zoro.com
2020/10/27 全球购物
信息技术课后反思
2014/04/27 职场文书
2014年医务科工作总结
2014/12/18 职场文书
个人工作违纪检讨书
2015/05/05 职场文书
幼儿园保教工作总结2015
2015/10/15 职场文书
Mac环境Nginx配置和访问本地静态资源的实现
2021/03/31 Servers
Java实现贪吃蛇游戏的示例代码
2022/09/23 Java/Android