Koa代理Http请求的示例代码


Posted in Javascript onOctober 10, 2018

Koa 代理http请求,解决跨域问题

1、为什么用Koa做跨域代理?

"最初为了解决跨域问题,我把站点部署到了nginx上就解决了问题。一次偶然的面试机会,面试官提出了一个假设我需要对提交api和api返回的数据进行适配,那么nginx是不是就无法满足了。当然这个问题的提出,让我考虑到其实如果自己搭一个站点,通过这个站点进行转发,适配第三方api的请求和应答不就好了。那么要搭一个站点的语言其实有很多,例如.net,java,nodejs,php...,那为什么最后选择nodejs呢?对于我来说最重要的原因,应该就是nodejs的轻量级和javascript语言亲和性。

2、搭建nodejs应用

由于Koa2刚出,毕竟学技术,那么就学最新的。

既然搭建程序那么就从程序的入口开始做,首先写程序的路由

const fs = require('fs')
const Router = require('koa-router');
const {httpHandle} = require('../Infrastructure/httpHandle');
const koaBody = require('koa-body')({
  multipart :true
});

const render = (page) => {
  return new Promise((resolve, reject) => {
    let viewUrl = `./view/${page}`
    fs.readFile(viewUrl, "binary", (err, data) => {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

let api = new Router();

api.get('*', httpHandle)
  .post('*', koaBody, httpHandle)
  .put('*', koaBody, httpHandle).del('*', koaBody, httpHandle);

let common = new Router();
common.get('*', async (ctx) => {
  ctx.body = await render('index.html');
})

let router = new Router();
router.use('/api', api.routes(), api.allowedMethods());
router.use('/', common.routes(), common.allowedMethods());
module.exports = router;

其次就是处理代理的请求

const httpRequest = (ctx) => {
  return new Promise((resolve) => {
    delete ctx.request.header.host;
    const options = {
      host,
      port,
      path: ctx.request.url.substr(4, ctx.request.url.length),
      method: ctx.request.method,
      headers: ctx.request.header
    }
    let requestBody='',
      body,
      head,
      chunks = [],
      fileFields,
      files,
      boundaryKey,
      boundary,
      endData,
      filesLength,
      totallength = 0;

    if (ctx.request.body) {
      console.log(ctx.request.header['content-type'])
      if (ctx.request.header['content-type'].indexOf('application/x-www-form-urlencoded') > -1) {
        requestBody = query.stringify(ctx.request.body);
        options.headers['Content-Length'] = Buffer.byteLength(requestBody)
      } else if (ctx.request.header['content-type'].indexOf('application/json') > -1) {
        requestBody = JSON.stringify(ctx.request.body);
        options.headers['Content-Length'] = Buffer.byteLength(requestBody)
      } else if (ctx.request.header['content-type'].indexOf('multipart/form-data') > -1) {
        fileFields = ctx.request.body.fields;
        files = ctx.request.body.files;
        boundaryKey = Math.random().toString(16);
        boundary = `\r\n----${boundaryKey}\r\n`;
        endData = `\r\n----${boundaryKey}--`;
        filesLength = 0;

        Object.keys(fileFields).forEach((key) => {
          requestBody += `${boundary}Content-Disposition:form-data;name="${key}"\r\n\r\n${fileFields[key]}`;
        })

        Object.keys(files).forEach((key) => {
          requestBody += `${boundary}Content-Type: application/octet-stream\r\nContent-Disposition: form-data; name="${key}";filename="${files[key].name}"\r\nContent-Transfer-Encoding: binary\r\n\r\n`;
          filesLength += Buffer.byteLength(requestBody,'utf-8') + files[key].size;
        })

        options.headers['Content-Type'] = `multipart/form-data; boundary=--${boundaryKey}`;
        options.headers[`Content-Length`] = filesLength + Buffer.byteLength(endData);
      } else {
        requestBody = JSON.stringify(ctx.request.body)
        options.headers['Content-Length'] = Buffer.byteLength(requestBody)
      }
    }

    const req = http.request(options, (res) => {
      res.on('data', (chunk) => {
        chunks.push(chunk);
        totallength += chunk.length;
      })

      res.on('end', () => {
        body = Buffer.concat(chunks, totallength);
        head = res.headers;
        resolve({head, body});
      })
    })

    ctx.request.body && req.write(requestBody);

    if (fileFields) {
      let filesArr = Object.keys(files);
      let uploadConnt = 0;
      filesArr.forEach((key) => {
        let fileStream = fs.createReadStream(files[key].path);
        fileStream.on('end', () => {
          fs.unlink(files[key].path);
          uploadConnt++;
          if (uploadConnt == filesArr.length) {
            req.end(endData)
          }
        })
        fileStream.pipe(req, {end: false})
      })
    } else {
      req.end();
    }

  })
}

由此简单的几行代码就实现了通过nodejs实现跨域的请求代理。 github链接

nginx代理config配置 如下

server {
   listen     1024; 
   server_name   tigrex:1024;
   root      home/TuoTuo.v2.UI;
   index      index.html;
   access_log   logs/tigrex.access.log;
   error_log    logs/tigrex.error.log;

   charset     utf-8;
   
   location /api {
     proxy_pass  http://127.0.0.1:1023/;
     proxy_set_header Host $host;
     proxy_redirect off;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   }  
   
   location / {
     try_files $uri $uri/ /index.html;     
    }
  }

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

Javascript 相关文章推荐
JavaScript Base64编码和解码,实现URL参数传递。
Sep 18 Javascript
细品javascript 寻址,闭包,对象模型和相关问题
Apr 27 Javascript
分享一个自定义的console类 让你不再纠结JS中的调试代码的兼容
Apr 20 Javascript
JavaScript中的稀疏数组与密集数组[译]
Sep 17 Javascript
jquery获取焦点和失去焦点事件代码
Apr 21 Javascript
JS组件Bootstrap Table表格行拖拽效果实现代码
Aug 27 Javascript
理解JavaScript中worker事件api
Dec 25 Javascript
Angular2 多级注入器详解及实例
Oct 30 Javascript
jQuery使用正则表达式替换dom元素标签用法示例
Jan 16 Javascript
解决微信内置浏览器返回上一页强制刷新问题方法
Feb 05 Javascript
基于vue+ bootstrap实现图片上传图片展示功能
May 17 Javascript
JavaScript数组去重实现方法小结
Jan 17 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
Oct 10 #Javascript
jQuery 获取除某指定对象外的其他对象 ( :not() 与.not())
Oct 10 #jQuery
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
Oct 09 #Javascript
从零开始封装自己的自定义Vue组件
Oct 09 #Javascript
vue axios 简单封装以及思考
Oct 09 #Javascript
angularJS实现不同视图同步刷新详解
Oct 09 #Javascript
对angular 实时更新模板视图的方法$apply详解
Oct 09 #Javascript
You might like
完美解决PHP中的Cannot modify header information 问题
2013/08/12 PHP
LAMP环境使用Composer安装Laravel的方法
2017/03/25 PHP
Laravel中为什么不使用blpop取队列详析
2018/08/01 PHP
PHP常见字符串操作函数与用法总结
2019/03/04 PHP
ThinkPHP框架整合微信支付之刷卡模式图文详解
2019/04/10 PHP
深入理解PHP+Mysql分布式事务与解决方案
2020/12/03 PHP
nodejs win7下安装方法
2012/05/24 NodeJs
js实现大转盘抽奖游戏实例
2015/06/24 Javascript
JS插件overlib用法实例详解
2015/12/26 Javascript
XML、HTML、CSS与JS的区别整理
2016/02/18 Javascript
详解Chai.js断言库API中文文档
2018/01/31 Javascript
关于Webpack dev server热加载失败的解决方法
2018/02/22 Javascript
在react-router4中进行代码拆分的方法(基于webpack)
2018/03/08 Javascript
AngularJS 监听变量变化的实现方法
2018/10/09 Javascript
vue实现自定义日期组件功能的实例代码
2018/11/06 Javascript
node.js学习笔记之koa框架和简单爬虫练习
2018/12/13 Javascript
五分钟搞懂Vuex实用知识(小结)
2019/08/12 Javascript
基于JavaScript实现简单抽奖功能代码实例
2020/10/20 Javascript
Python使用redis pool的一种单例实现方式
2016/04/16 Python
Python使用re模块实现信息筛选的方法
2018/04/29 Python
解决Django的request.POST获取不到内容的问题
2018/05/28 Python
用openCV和Python 实现图片对比,并标识出不同点的方式
2019/12/19 Python
iHerb俄罗斯:维生素、补品和天然产品
2020/07/09 全球购物
Belvilla法国:休闲度假房屋出租
2020/10/03 全球购物
什么时候需要进行强制类型转换
2016/09/03 面试题
机械制造专业个人的自我评价
2013/12/28 职场文书
简历里的自我评价范文
2014/02/24 职场文书
文明村镇申报材料
2014/05/06 职场文书
欢迎家长标语
2014/10/08 职场文书
医生见习报告范文
2014/11/03 职场文书
毕业生评语大全
2015/01/04 职场文书
企业百日安全活动总结
2015/05/07 职场文书
二十年同学聚会感言
2015/07/30 职场文书
Python深度学习之实现卷积神经网络
2021/06/05 Python
Mysql分库分表之后主键处理的几种方法
2022/02/15 MySQL
HTML中的表格元素介绍
2022/02/28 HTML / CSS