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表达式中连续的 && 和 || 之赋值区别
Oct 17 Javascript
JS拖动技术 关于setCapture使用
Dec 09 Javascript
仿猪八戒网左下角的文字滚动效果
Oct 28 Javascript
js判断上传文件类型判断FileUpload文件类型代码
May 20 Javascript
JS的框架Polymer中的dom-if和is属性使用说明
Jul 29 Javascript
在Html中使用Requirejs进行模块化开发实例详解
Apr 15 Javascript
jQuery实现侧浮窗与中浮窗切换效果的方法
Sep 05 Javascript
Bootstrap Navbar Component实现响应式导航
Oct 08 Javascript
浅谈vue实现数据监听的函数 Object.defineProperty
Jun 08 Javascript
js实现扫雷小程序的示例代码
Sep 27 Javascript
通过jquery获取上传文件名称、类型和大小的实现代码
Apr 19 jQuery
vue下拉菜单组件(含搜索)的实现代码
Nov 25 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 json转换成数组形式代码分享
2014/11/10 PHP
Yii的Srbac插件用法详解
2016/07/14 PHP
JavaScript 继承详解 第一篇
2009/08/30 Javascript
Javascript结合css实现网页换肤功能
2009/11/02 Javascript
javascript获取select的当前值示例代码(兼容IE/Firefox/Opera/Chrome)
2013/12/17 Javascript
angularjs 处理多个异步请求方法汇总
2015/01/06 Javascript
谈谈我对JavaScript DOM事件的理解
2015/12/18 Javascript
关于Javascript中defer和async的区别总结
2016/09/20 Javascript
Vue2.x中的父组件传递数据至子组件的方法
2017/05/01 Javascript
JS获取填报扩展单元格控件的值的解决办法
2017/07/14 Javascript
Vue添加请求拦截器及vue-resource 拦截器使用
2017/11/23 Javascript
vue+echarts实现可拖动节点的折线图(支持拖动方向和上下限的设置)
2019/04/12 Javascript
微信小程序工具函数封装
2019/10/28 Javascript
Vue的全局过滤器和私有过滤器的实现
2020/04/20 Javascript
基于openlayers实现角度测量功能
2020/09/28 Javascript
[46:00]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第一局
2016/03/03 DOTA
[01:01:22]VGJ.S vs OG 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
用Python编写简单的微博爬虫
2016/03/04 Python
Python实现优先级队列结构的方法详解
2016/06/02 Python
python分析作业提交情况
2017/11/22 Python
使用python 爬虫抓站的一些技巧总结
2018/01/10 Python
wxpython实现图书管理系统
2018/03/12 Python
pygame游戏之旅 添加icon和bgm音效的方法
2018/11/21 Python
python numpy数组中的复制知识解析
2020/02/03 Python
tf.concat中axis的含义与使用详解
2020/02/07 Python
使用openCV去除文字中乱入的线条实例
2020/06/02 Python
CSS3 真的会替代 SCSS 吗
2021/03/09 HTML / CSS
阿里云:Aliyun.com
2017/02/15 全球购物
荷兰多品牌网上鞋店:Stoute Schoenen
2017/08/24 全球购物
eBay荷兰购物网站:eBay.nl
2020/06/26 全球购物
yy生日主持词
2014/03/20 职场文书
廉洁家庭事迹材料
2014/05/15 职场文书
社区平安建设方案
2014/05/25 职场文书
保护地球的标语
2014/06/17 职场文书
经营场所使用证明
2015/06/19 职场文书
python3中apply函数和lambda函数的使用详解
2022/02/28 Python