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中this关键字使用方法详解
Mar 08 Javascript
jquery 入门教程 [翻译] 推荐
Aug 17 Javascript
AngularJS内置指令
Feb 04 Javascript
JavaScript中用getDate()方法返回指定日期的教程
Jun 09 Javascript
几种经典排序算法的JS实现方法
Mar 25 Javascript
Jquery uploadify 多余的Get请求(404错误)的解决方法
Jan 26 Javascript
jQuery实现字体颜色渐变效果的方法
Mar 29 jQuery
利用PM2部署node.js项目的方法教程
May 10 Javascript
详解Vue 全局变量,局部变量
Apr 17 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
May 10 Javascript
Vue点击切换Class变化,实现Active当前样式操作
Jul 17 Javascript
处理canvas绘制图片模糊问题
May 11 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函数的基本应用
2011/07/14 PHP
win7计划任务定时执行PHP脚本设置图解
2014/05/09 PHP
浅析php原型模式
2014/11/25 PHP
php+mysqli实现批量替换数据库表前缀的方法
2014/12/29 PHP
php判断linux下程序问题实例
2015/07/09 PHP
yii2实现根据时间搜索的方法
2016/05/25 PHP
PHP经典设计模式之依赖注入定义与用法详解
2019/05/21 PHP
做网页的一些技巧
2007/02/01 Javascript
js 动态文字滚动的例子
2011/01/17 Javascript
jQuery contains过滤器实现精确匹配使用方法
2013/04/12 Javascript
介绍一个简单的JavaScript类框架
2015/06/24 Javascript
js实现浏览器倒计时跳转页面效果
2016/08/12 Javascript
ajax请求data遇到的问题分析
2018/01/18 Javascript
解决小程序无法触发SESSION问题
2020/02/03 Javascript
[05:45]Ti4观战指南(下)
2014/07/07 DOTA
[10:34]DOTA2上海特级锦标赛全纪录
2016/03/25 DOTA
在win和Linux系统中python命令行运行的不同
2016/07/03 Python
Python3实现爬取简书首页文章标题和文章链接的方法【测试可用】
2018/12/11 Python
Python中调用其他程序的方式详解
2019/08/06 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
2020/01/06 Python
python统计字符串中字母出现次数代码实例
2020/03/02 Python
Python decorator拦截器代码实例解析
2020/04/04 Python
基于python实现操作git过程代码解析
2020/07/27 Python
爬虫代理的cookie如何生成运行
2020/09/22 Python
Python如何使用vars返回对象的属性列表
2020/10/17 Python
使用phonegap播放音频的实现方法
2017/03/31 HTML / CSS
博士研究生自我鉴定范文
2013/12/04 职场文书
物业工作计划书
2014/01/10 职场文书
幼儿园大班见习报告
2014/10/31 职场文书
小升初自荐信怎么写
2015/03/26 职场文书
Nginx的rewrite模块详解
2021/03/31 Servers
Pytorch 使用tensor特定条件判断索引
2021/04/08 Python
python 利用PyAutoGUI快速构建自动化操作脚本
2021/05/31 Python
浅谈TypeScript 索引签名的理解
2021/10/16 Javascript
Python OpenCV超详细讲解调整大小与图像操作的实现
2022/04/02 Python
零基础学java之循环语句的使用
2022/04/10 Java/Android