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 相关文章推荐
poshytip 基于jquery的 插件 主要用于显示微博人的图像和鼠标提示等
Oct 12 Javascript
jQuery简单图表peity.js使用示例
May 02 Javascript
浅析JQuery中的html(),text(),val()区别
Sep 01 Javascript
jquery使用remove()方法删除指定class子元素
Mar 26 Javascript
Jquery和angularjs获取check框选中的值的方法汇总
Jan 17 Javascript
Bootstrap 粘页脚效果
Mar 28 Javascript
基于JQuery实现图片上传预览与删除操作
May 24 Javascript
jQuery属性选择器用法示例
Sep 09 Javascript
Vue.directive自定义指令的使用详解
Mar 10 Javascript
javascript 动态生成css代码的两种方法
Mar 17 Javascript
angular+webpack2实战例子
May 23 Javascript
JQuery 又谈ajax局部刷新
Nov 27 jQuery
解决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
调整优化您的LAMP应用程序的5种简单方法
2011/06/26 PHP
解析阿里云ubuntu12.04环境下配置Apache+PHP+PHPmyadmin+MYsql
2013/06/26 PHP
关于使用key/value数据库redis和TTSERVER的心得体会
2013/06/28 PHP
phpphp图片采集后按原路径保存图片示例
2014/02/18 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
2017/12/25 PHP
Javascript 鼠标移动上去 滑块跟随效果代码分享
2013/11/23 Javascript
javascript中的括号()用法小结
2014/04/14 Javascript
教你用AngularJS框架一行JS代码实现控件验证效果
2014/06/23 Javascript
JS实现在页面随时自定义背景颜色的方法
2015/02/27 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
JavaScript随机生成信用卡卡号的方法
2015/04/07 Javascript
jQuery+html5实现div弹出层并遮罩背景
2015/04/15 Javascript
JS+CSS实现大气清新的滑动菜单效果代码
2015/10/22 Javascript
基于jQuery实现的查看全文功能【实用】
2016/12/11 Javascript
原生js实现旋转木马轮播图效果
2017/02/27 Javascript
webstorm添加vue.js支持的方法教程
2017/07/05 Javascript
详解vue项目打包后通过百度的BAE发布到网上的流程
2018/03/05 Javascript
React Navigation 使用中遇到的问题小结
2018/05/08 Javascript
浅析JS中回调函数及用法
2018/07/25 Javascript
JavaScript fetch接口案例解析
2018/08/30 Javascript
ES6入门教程之let、const的使用方法
2019/04/13 Javascript
简单了解Javscript中兄弟ifream的方法调用
2019/06/17 Javascript
JS中超越现实的匿名函数用法实例分析
2019/06/21 Javascript
JavaScript canvas绘制折线图
2020/02/18 Javascript
React Ant Design树形表格的复杂增删改操作
2020/11/02 Javascript
js用正则表达式筛选年月日的实例方法
2021/01/04 Javascript
Python对列表排序的方法实例分析
2015/05/16 Python
详解字典树Trie结构及其Python代码实现
2016/06/03 Python
python计算两个矩形框重合百分比的实例
2018/11/07 Python
Python实现定期检查源目录与备份目录的差异并进行备份功能示例
2019/02/27 Python
python实现126邮箱发送邮件
2020/05/20 Python
售后服务承诺书怎么写
2014/05/21 职场文书
活动总结模板大全
2015/05/11 职场文书
Nginx解决403 forbidden的完整步骤
2021/04/01 Servers
Python中的min及返回最小值索引的操作
2021/05/10 Python
以MySQL5.7为例了解一下执行计划
2022/04/13 MySQL