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 相关文章推荐
JQuery Ajax 跨域访问的解决方案
Mar 12 Javascript
jquery easyui滚动条部分设置介绍
Sep 12 Javascript
JavaScript中的函数的两种定义方式和函数变量赋值
May 12 Javascript
extjs_02_grid显示本地数据、显示跨域数据
Jun 23 Javascript
JS跨域问题详解
Nov 25 Javascript
javascript 原型链维护和继承详解
Nov 26 Javascript
实例讲解jquery中mouseleave和mouseout的区别
Feb 17 Javascript
js 求时间差的实现代码
Apr 26 Javascript
js操作浏览器的参数方法
Jan 21 Javascript
详解Vue中一种简易路由传参办法
Sep 15 Javascript
JavaScript运行机制实例分析
Apr 11 Javascript
Vue 列表页带参数进详情页的操作(router-link)
Nov 13 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
域名和cookie问题(域名后缀)
2012/10/10 PHP
php中get_defined_constants函数用法实例分析
2015/05/12 PHP
Linux安装配置php环境的方法
2016/01/14 PHP
比较详细的关于javascript 解析json的代码
2009/12/16 Javascript
jquery异步调用页面后台方法‏(asp.net)
2011/03/01 Javascript
使用js实现雪花飘落效果
2013/08/26 Javascript
js中的setInterval和setTimeout使用实例
2014/05/09 Javascript
JS实现点击颜色块切换指定区域背景颜色的方法
2015/02/25 Javascript
小议JavaScript中Generator和Iterator的使用
2015/07/29 Javascript
javascript显示倒计时控制按钮的简单实现
2016/06/07 Javascript
利用BootStrap弹出二级对话框的简单实现方法
2016/09/21 Javascript
JavaScript“尽快失败”的原则实例详解
2016/10/08 Javascript
微信小程序商城项目之侧栏分类效果(1)
2017/04/17 Javascript
jQuery模拟实现天猫购物车动画效果实例代码
2017/05/25 jQuery
JS实现批量上传文件并显示进度功能
2017/06/27 Javascript
jQuery中extend函数简单用法示例
2017/10/11 jQuery
jQuery实现炫丽的3d旋转星空效果
2018/07/04 jQuery
vue路由对不同界面进行传参及跳转的总结
2019/04/20 Javascript
js如何验证密码强度
2020/03/18 Javascript
解决vue props传Array/Object类型值,子组件报错的情况
2020/11/07 Javascript
基础的十进制按位运算总结与在Python中的计算示例
2016/06/28 Python
Python3 伪装浏览器的方法示例
2017/11/23 Python
python中subprocess批量执行linux命令
2018/04/27 Python
pandas分区间,算频率的实例
2019/07/04 Python
英国综合网上购物商城:The Hut
2018/07/03 全球购物
Travelstart沙特阿拉伯:廉价航班、豪华酒店和实惠的汽车租赁优惠
2019/04/06 全球购物
如何理解transaction事务的概念
2015/05/27 面试题
会计电算化应届生求职信
2013/11/03 职场文书
护士自荐信范文
2013/12/15 职场文书
审计主管岗位职责
2014/01/31 职场文书
2015年数学教研组工作总结
2015/05/23 职场文书
2016新年致辞
2015/08/01 职场文书
小学作文指导之如何写人?
2019/07/08 职场文书
Vue通过懒加载提升页面响应速度
2021/05/10 Vue.js
Python实现提取PDF简历信息并存入Excel
2022/04/02 Python
Golang实现可重入锁的示例代码
2022/05/25 Golang