时间:2021-07-01 10:21:17 帮助过:14人阅读
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;
- }
- }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。