Koa代理Http请求的示例代码

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;
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解基于Node.js的HTTP/2 Server实践

    虽然HTTP/2目前已经逐渐的在各大网站上开始了使用,但是在目前最新的Node.js上仍然处于实验性API,还没有能有效解决生产环境各种问题的应用示例.因此在应用HTTP/2的道路上我自己也遇到了许多坑,下面介绍了项目的主要架构与开发中遇到的问题及解决方式,也许会对你有一点点启示. 配置 虽然W3C的规范中没有规定HTTP/2协议一定要使用ssl加密,但是支持非加密的HTTP/2协议的浏览器实在少的可怜,因此我们有必要申请一个自己的域名和一个ssl证书. 本项目的测试域名是 you.keyin.

  • nodejs发送http请求时遇到404长时间未响应的解决方法

    通常,我们在使用nodejs发送http请求时,一旦遇到404响应,nodejs内部会一直请求下去,直到超出它自己设定的响应时长(最让人恶心的地方就是这个时长还是没法修改的.)很多人在这里碰到了麻烦. 我是在做arcgis地图项目的时候,客户提出需要使用天地图提供的底图服务,当时我直接使用silverlight客户端的Arcgis API进行http请求(同样是内部请求,不开源的东西就是这么让人郁闷),同样碰到了一个进度条一直卡在那的问题.经过调试发现,是由于底图加载请求超时的缘故,和nodej

  • 深入理解node.js http模块

    http模块主要用于搭建HTTP服务端和客户端,使用HTTP服务器或客户端功能都必须调用http模块. 创建服务器 var http = require("http");var url = require("url");//创建服务器//http继承自tcpvar server = http.createServer(function (req,res) { var urlstr = req.url;//获取请求的路径 var urlMethod = req.met

  • 详解node.js的http模块实例演示

    上世纪六七十年代,红岸基地一直在向茫茫外太空发送讯号,当叶文洁通过太阳作为广播,将地球的讯号向外发送时,宇宙的各个先进文明都接收到了讯号,其中就包括了离我们最近的三体星. 本篇用node.js的http模块模拟这一事件. let http = require('http') // 创建一个web服务器 let server = http.createServer() server.on('request', function () { console.log('我们接收到了一个用原始膜发送讯号的

  • Node.js进阶之核心模块https入门

    模块概览 这个模块的重要性,基本不用强调了.在网络安全问题日益严峻的今天,网站采用HTTPS是个必然的趋势. 在nodejs中,提供了 https 这个模块来完成 HTTPS 相关功能.从官方文档来看,跟 http 模块用法非常相似. 本文主要包含两部分: 通过客户端.服务端的例子,对https模块进行入门讲解. 如何访问安全证书不受信任的网站.(以 12306 为例子) 篇幅所限,本文无法对 HTTPS协议 及 相关技术体系 做过多讲解,有问题欢迎留言交流. 客户端例子 跟http模块的用法非

  • Node.js学习教程之HTTP/2服务器推送【译】

    前言 最近Node.js v8.4+版本发布带来了体验版的HTTP/2,你可以自己通过设置参数--expose-http2启动. 这篇文章,我将介绍HTTP/2最重要的一方面服务器推送并且创建一个小的Node.js程序案例来使用它.下面话不多说了,来一起看看详细的介绍吧. 关于HTTP/2 HTTP/2 的目的是通过支持完整的请求与响应复用来减少延迟,通过有效压缩 HTTP 标头字段将协议开销降至最低,同时增加对请求优先级和服务器推送的支持. 更多关于HTTP/2内容,请查看文章HTTP/2.

  • 基于node下的http小爬虫的示例代码

    每时每刻不管你睡了还是没睡,互联网都会有海量的数据来来往往,有客服端到服务端,有服务端到服务端.http的get和request完成的角色即为数据的获取及提交,接下来我们动手写一个简单的小爬虫来爬爬菜鸟教程中关于node的章节的课程界面. 爬取Node.js 教程首页的所有数据 建立node-http.js,其中代码如下,代码中有详细的的注释,自行理解了哈 var http=require('http');//获取http模块 var url='http://www.runoob.com/nod

  • Node启动https服务器的教程

    首先你需要生成https证书,可以去付费的网站购买或者找一些免费的网站,可能会是key或者crt或者pem结尾的.不同格式之间可以通过OpenSSL转换,如: openssl x509 -in mycert.crt -out mycert.pem -outform PEM Node原生版本: const https = require('https') const path = require('path') const fs = require('fs') // 根据项目的路径导入生成的证书文

  • node.js中http模块和url模块的简单介绍

    前言 本文主要给大家介绍了关于node.js中http模块与url模块的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.http模块的简单介绍 node.js当中的http内置模块可以用于创建http服务器与http客户端. 1.引包 const http = require('http'); 2.创建http服务器 var server = http.createServer((req,res)=>{ }); 使用http的.createServer()方法可以

  • Koa代理Http请求的示例代码

    Koa 代理http请求,解决跨域问题 1.为什么用Koa做跨域代理? "最初为了解决跨域问题,我把站点部署到了nginx上就解决了问题.一次偶然的面试机会,面试官提出了一个假设我需要对提交api和api返回的数据进行适配,那么nginx是不是就无法满足了.当然这个问题的提出,让我考虑到其实如果自己搭一个站点,通过这个站点进行转发,适配第三方api的请求和应答不就好了.那么要搭一个站点的语言其实有很多,例如.net,java,nodejs,php...,那为什么最后选择nodejs呢?对于我来说

  • NodeJS收发GET和POST请求的示例代码

    本文介绍了NodeJS收发GET和POST请求的示例代码,分享给大家,也给自己留个笔记 一 express框架接收 app.get('/',function(req,res) { var url = req.query.url; var name = req.query.name; console.log(url, name); }); 二 接收Get 1. get参数在req.url上 2. 使用url.parse将数据由字符串转变为obj index.js: var http = requi

  • Nginx限制某个IP同一时间段的访问次数和请求数示例代码

    nginx可以通过ngx_http_limit_conn_module和ngx_http_limit_req_module配置来限制ip在同一时间段的访问次数. ngx_http_limit_conn_module:该模块用于限制每个定义的密钥的连接数,特别是单个IP​​地址的连接数.使用limit_conn_zone和limit_conn指令. ngx_http_limit_req_module:用于限制每一个定义的密钥的请求的处理速率,特别是从一个单一的IP地址的请求的处理速率.使用"泄漏桶

  • JavaScript实现串行请求的示例代码

    使用async和await var fn = async function(promiseArr) { for(let i = 0,len = arr.length; i<len; i++) { currentPromise = (promiseArr[i] instanceOf Promise) ? promiseArr[i] : Promise.resolve(promiseArr[i]); var result = await currentPromise; console.log(res

  • Golang发送http GET请求的示例代码

    使用标准库http来实现 package tools import ( "io/ioutil" "net/http" ) func Get(url string)string{ res, err :=http.Get(url) if err != nil { return "" } robots, err := ioutil.ReadAll(res.Body) res.Body.Close() if err != nil { return &qu

  • golang NewRequest/gorequest实现http请求的示例代码

    通过go语言实现http请求 http.Post import (     "net/http"     "net/url" ) data := url.Values{"start":{"100"}, "hobby":{"xxxx"}} body := strings.NewReader(data.Encode()) resp, err := http.Post("127.0.

  • Java使用CountDownLatch实现网络同步请求的示例代码

    CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行. 这里是使用CountDownLatch和多线程完成商品信息异步组装: import java.time.LocalDateTime; import java.util.StringJoiner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorS

  • React Native 使用Fetch发送网络请求的示例代码

    我们在项目中经常会用到HTTP请求来访问网络,HTTP(HTTPS)请求通常分为"GET"."PUT"."POST"."DELETE",如果不指定默认为GET请求. 在项目中我们常用到的一般为GET和POST两种请求方式,针对带参数的表单提交这类的请求,我们通常会使用POST的请求方式. 为了发出HTTP请求,我们需要使用到 React Native 提供的 Fetch API 来进行实现.要从任意地址获取内容的话,只需简单地

  • SpringMVC处理multipart请求的示例代码

    一.简述 multipart格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域.在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是二进制.类似这样: 二. 配置 multipart 解析器 尽管multipart请求看起来很复杂,但在Spring MVC中处理它们却很容易.在编写控制器方法处理文件上传之前,我们必须要配置一个multipart解析器,通过它来告诉DispatcherServlet该如何读取multipart请求

  • koa socket即时通讯的示例代码

    前言 http的特点是一问一答,而即时通讯是需要双向通信的,这样以前的即时通信只能使用轮询的方式通过周期性的ajax请求获取数据,直到websocket出现,就完美实现了双向通信 一 即时通讯方式简介 段轮询 前台使用setInterval进行定时请求后台,这样无疑非常浪费性能 长轮询和长连接(html5的EventSource) 客服端连接一次,服务端不断开连接,服务端接收到新消息就发送给前台,客服端和服务端保持一直连接,缺点是只有服务端向客服端输出 websocket websocket不再

随机推荐