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 日期时间函数(经典+完善+实用)
May 27 Javascript
firefox和IE系列的相关区别整理 以备后用
Dec 28 Javascript
JavaScript 轻松搞定快捷留言功能 只需一行代码
Apr 01 Javascript
javascript中"/"运算符常见错误
Oct 13 Javascript
深入解析JavaScript编程中的this关键字使用
Nov 09 Javascript
JS数组排序技巧汇总(冒泡、sort、快速、希尔等排序)
Nov 24 Javascript
由简入繁实现Jquery树状结构的方法(推荐)
Jun 10 Javascript
js 自带的 map() 方法全面了解
Aug 16 Javascript
文件上传插件SWFUpload的使用指南
Nov 29 Javascript
详解Nuxt.js中使用Element-UI填坑
Sep 06 Javascript
javascript实现贪吃蛇游戏(娱乐版)
Aug 17 Javascript
原生js实现表格循环滚动
Nov 24 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与MYSql连接与查询
2011/07/14 PHP
Web程序工作原理详解
2014/12/25 PHP
Java和PHP在Web开发方面对比分析
2015/03/01 PHP
JS在TextArea光标位置插入文字并实现移动光标到文字末尾
2013/06/21 Javascript
jQuery的cookie插件实现保存用户登陆信息
2014/04/15 Javascript
js下将阿拉伯数字每三位一逗号分隔(如:15000000转化为15,000,000)
2014/06/02 Javascript
js实现正方形颜色从下往上升的效果
2014/08/04 Javascript
jquery动态添加删除(tr/td)
2015/02/09 Javascript
JavaScript中指定函数名称的相关方法
2015/06/04 Javascript
JavaScript与HTML的结合方法详解
2015/11/23 Javascript
jQuery事件绑定用法详解
2016/09/08 Javascript
Javascript实现倒计时(防页面刷新)实例
2016/12/13 Javascript
JS基于正则截取替换特定字符之间字符串操作示例
2017/02/03 Javascript
详解React Native网络请求fetch简单封装
2017/08/10 Javascript
封装运动框架实战左右与上下滑动的焦点轮播图(实例)
2017/10/17 Javascript
Angular4学习教程之DOM属性绑定详解
2018/01/04 Javascript
小程序图片剪裁加旋转的示例代码
2018/07/10 Javascript
vue权限路由实现的方法示例总结
2018/07/29 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
react写一个select组件的实现代码
2019/04/03 Javascript
Vue使用JSEncrypt实现rsa加密及挂载方法
2020/02/07 Javascript
Javascript数组及类数组相关原理详解
2020/10/29 Javascript
vue打开新窗口并实现传参的图文实例
2021/03/04 Vue.js
Android应用开发中Action bar编写的入门教程
2016/02/26 Python
Python爬虫中urllib库的进阶学习
2018/01/05 Python
python中利用zfill方法自动给数字前面补0
2018/04/10 Python
如何利用python制作时间戳转换工具详解
2018/09/12 Python
解决pycharm同一目录下无法import其他文件
2020/02/12 Python
Flask缓存静态文件的具体方法
2020/08/02 Python
使用jquery实现HTML5响应式导航菜单教程
2014/04/02 HTML / CSS
房屋买卖协议书范本
2014/04/10 职场文书
民主生活会主持词
2015/07/01 职场文书
一年级下册数学教学反思
2016/02/16 职场文书
《春酒》教学反思
2016/02/22 职场文书
详解Vue slot插槽
2021/11/20 Vue.js
SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法
2022/07/07 Java/Android