美文网首页node
Koa代理Http请求

Koa代理Http请求

作者: ChrysAwesome | 来源:发表于2017-09-04 14:15 被阅读3234次

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

    相关文章

      网友评论

        本文标题:Koa代理Http请求

        本文链接:https://www.haomeiwen.com/subject/tbosjxtx.html