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实现检测浏览器及版本的脚本代码
Jan 22 Javascript
JS将所有对象s的属性复制给对象r(原生js+jquery)
Jan 25 Javascript
js中定义一个变量并判断其是否为空的方法
May 13 Javascript
jQuery级联操作绑定事件实例
Sep 02 Javascript
JQuery 使用attr方法实现下拉列表选中
Oct 13 Javascript
jquery表单验证插件(jquery.validate.js)的3种使用方式
Mar 28 Javascript
jquery插件orbit.js实现图片折叠轮换特效
Apr 14 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
Jun 12 Javascript
javascript自定义事件功能与用法实例分析
Nov 08 Javascript
JS重学系列之聊聊new操作符
Mar 04 Javascript
JS在Array数组中按指定位置删除或添加元素对象方法示例
Nov 19 Javascript
Vue数字输入框组件使用方法详解
Feb 10 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
回首过去10年中最搞笑的10部动漫,哪一部让你节操尽碎?
2020/03/03 日漫
php用正则表达式匹配中文实例详解
2013/11/06 PHP
Linux下创建nginx脚本-start、stop、reload…
2014/08/03 PHP
Laravel构建即时应用的一种实现方法详解
2017/08/31 PHP
微信公众平台开发教程④ ThinkPHP框架下微信支付功能图文详解
2019/04/10 PHP
List the Stored Procedures in a SQL Server database
2007/06/20 Javascript
javascript 表单的友好用户体现
2009/01/07 Javascript
jquery中常用的SET和GET
2009/01/13 Javascript
基于JQuery.timer插件实现一个计时器
2010/04/25 Javascript
IE8 中使用加速器(Activities)
2010/05/14 Javascript
JavaScript动态调整TextArea高度的代码
2010/12/28 Javascript
JQuery设置文本框和密码框得到焦点时的样式
2013/08/30 Javascript
基于JQuery的列表拖动排序实现代码
2013/10/01 Javascript
使用jQuery和PHP实现类似360功能开关效果
2014/02/12 Javascript
js继承call()和apply()方法总结
2014/12/08 Javascript
简介JavaScript中的setHours()方法的使用
2015/06/11 Javascript
jQuery实现动画效果circle实例
2015/08/06 Javascript
BootStrap Typeahead自动补全插件实例代码
2016/08/10 Javascript
JavaScript事件冒泡与事件捕获实例分析
2018/08/01 Javascript
vue路由守卫+登录态管理实例分析
2019/05/21 Javascript
vue实现分页栏效果
2019/06/28 Javascript
[01:19:35]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第二局
2016/03/05 DOTA
Python删除空文件和空文件夹的方法
2015/07/14 Python
Python正则表达式经典入门教程
2017/05/22 Python
python交易记录链的实现过程详解
2019/07/03 Python
Python函数必须先定义,后调用说明(函数调用函数例外)
2020/06/02 Python
python基于opencv实现人脸识别
2021/01/04 Python
英语专业毕业生自荐信
2013/10/28 职场文书
行政助理岗位职责范文
2013/12/03 职场文书
网络编辑岗位职责范本
2014/02/10 职场文书
倡议书格式范文
2014/04/14 职场文书
创意婚礼策划方案
2014/05/18 职场文书
课外访万家心得体会
2014/09/03 职场文书
龙门石窟导游词
2015/02/02 职场文书
SQL SERVER中常用日期函数的具体使用
2021/04/08 SQL Server
总结一下关于在Java8中使用stream流踩过的一些坑
2021/06/24 Java/Android