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 相关文章推荐
通过一段代码简单说js中的this的使用
Jul 23 Javascript
点击进行复制的JS代码实例
Aug 23 Javascript
JS获取当前日期和时间的简单实例
Nov 19 Javascript
jQuery(js)获取文字宽度(显示长度)示例代码
Dec 31 Javascript
Javascript自定义函数判断网站访问类型是PC还是移动终端
Jan 10 Javascript
JS操作CSS随机改变网页背景实现思路
Mar 10 Javascript
Position属性之relative用法
Dec 14 Javascript
node.js实现端口转发
Apr 14 Javascript
JavaScript常见事件处理程序实例总结
Jan 05 Javascript
JavaScript迭代器的含义及用法
Jun 21 Javascript
Vue的路由及路由钩子函数的实现
Jul 02 Javascript
Vue.js如何使用Socket.IO的示例代码
Sep 05 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几个算法:PHP冒泡、PHP二分法、PHP求素数、PHP乘法表
2013/06/06 PHP
[原创]PHP实现SQL语句格式化功能的方法
2017/07/28 PHP
javascript延时重复执行函数 lLoopRun.js
2007/06/29 Javascript
jquery实现带复选框的表格行选中删除时高亮显示
2013/08/01 Javascript
jquery实现input框获取焦点的方法
2017/02/06 Javascript
vue项目实现设置根据路由高亮对应的菜单项操作
2020/08/06 Javascript
[01:06:12]VP vs NIP 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
在Django中使用Sitemap的方法讲解
2015/07/22 Python
编写Python爬虫抓取豆瓣电影TOP100及用户头像的方法
2016/01/20 Python
Pycharm学习教程(3) 代码运行调试
2017/05/03 Python
利用Python操作消息队列RabbitMQ的方法教程
2017/07/19 Python
python模拟表单提交登录图书馆
2018/04/27 Python
浅析python中的迭代与迭代对象
2018/10/08 Python
python linecache 处理固定格式文本数据的方法
2019/01/08 Python
python实现五子棋小游戏
2020/03/25 Python
PyQt5 实现字体大小自适应分辨率的方法
2019/06/18 Python
使用python serial 获取所有的串口名称的实例
2019/07/02 Python
python实现名片管理器的示例代码
2019/12/17 Python
Python如何基于rsa模块实现非对称加密与解密
2020/01/03 Python
Tensorflow获取张量Tensor的具体维数实例
2020/01/19 Python
animation和transition的区别
2020/10/12 HTML / CSS
编写函数,将一个3*3矩阵转置
2013/10/09 面试题
中科方德软件测试面试题
2016/04/21 面试题
初三政治教学反思
2014/01/30 职场文书
歌颂祖国的演讲稿
2014/05/04 职场文书
办理护照工作证明
2014/10/10 职场文书
思想政治表现评语
2015/01/04 职场文书
2015年母亲节活动策划方案
2015/05/04 职场文书
最感人的道歉情书
2015/05/12 职场文书
逃出克隆岛观后感
2015/06/09 职场文书
2015年电气技术员工作总结
2015/07/24 职场文书
田径运动会广播稿
2015/08/19 职场文书
2016年教师学习廉政准则心得体会
2016/01/20 职场文书
人民币使用说明书
2019/04/17 职场文书
python 如何执行控制台命令与操作剪切板
2021/05/20 Python
简单谈谈Python面向对象的相关知识
2021/06/28 Python