代码改变世界

解决异地服务器接口访问跨域,node构建反向代理

2017-09-08 18:02  muamaker  阅读(1141)  评论(0编辑  收藏  举报

     跨域对于前端来说是一个老大难的问题,许多方法如jsonpdocument.domain + iframe...都有或多或少的问题,一个最佳实践就是通过服务器nginx做反向代理,但奈何不懂相关知识,就一直琢磨着使用 node.js来做。

 

  之前公司php写的接口,然后用node定义一样的路由,前端请求node的接口,然后通过Node在控制器中访问php的接口,这样确实能解决跨域问题,不过也是有缺点的,不能带上cookic等信息,不等同于反向代理;

  

  事实上使用node是可以很容易构建本地的反向代理,使用 http-proxy-middleware 模块

  假如目前有一个php提供的接口为   http://api.text.com/getdata  需要去代理

  首先  

npm i  http-proxy-middleware --save   //反向代理包
npm i cors  --save            //node跨域模块 

 然后:生成一个新的 express,app.js里面 删掉 index和user这两个路由,然后

var cors = require('cors');
var proxy = require('http-proxy-middleware');
var options = {
    target: 'http://api.text.com', // 目标主机,提供接口服务的域名
    changeOrigin: true,               // 需要虚拟主机站点
};
var exampleProxy = proxy(options);  //开启代理功能,并加载配置

 

  

app.use(cors());

app.use(exampleProxy);  //代理任意请求的路由,也可以改成代理固定的某些路由

启动express服务

 

前段代码:

const host = "http://127.0.0.1:3000";
$.ajax({
url: host+ "/getdata"
}).then(function(data){
console.log(data);
}).fail(function(error){
console.log(error);
});

目前为止,反向代理成功,本地电脑可以跨域访问远程服务接口

 

 

 

另外,附加上,自己写的一个,携带cookic 的转发:

roouter.js 文件

var express = require('express');
var router = express.Router();
var request = require("request");
/* GET home page. */



const Api = {
	GET(params){
		params = params || {};
		return new Promise(function(resolve,reject){
			request({
				method:"GET",
				url:params.url,
				qs:params.data,
				headers:params.headers
			},function (error, response, body) {
			    if (!error) {
					resolve({response,body});
			    }else{
					reject(error);
			    }
			});
		})
		
	},
	POST(params){
		params = params || {};
		return new Promise(function(resolve,reject){
			request({
				method:"POST",
				url:params.url,
				form:params.data,
				headers:params.headers
			},function (error, response, body) {
			    if (!error) {
					resolve({response,body});
			    }else{
					reject(error);
			    }
			});
		})
	}
}



module.exports = function(opt){
	opt  = opt || {};
	var target = opt.target || '';
	var url = opt.url || "**";
	router.all(url,function(req,res,next){
		var url = target + req.baseUrl + req.path;
		var data = {};
		var method = req.method;
		if(method =="GET"){
			data = req.query;
		}else if(method == "POST"){
			data = req.body;
		}
		let Cookie =  req.header("Cookie");
		let content = req.header('Content-type');
		console.log("url:"+url,data,Cookie,content);
		data.headers = {
			"content-type": content,
			"Cookie":Cookie
		};
		if(Api[req.method]){
			Api[req.method]({
				url:url,
				data:data
			}).then(function({response,body}){
				try{
					body = JSON.parse(body);
				}catch(e){
				}
				// ************** 透传响应中的cookie **************
                if (response.headers['set-cookie']) {
                    res.setHeader("set-cookie", response.headers['set-cookie']);
				}
				
                // ************** 自定义cookie **************
				//res.cookie('tc', 'test-cookie', {maxAge: 2 * 60 * 60 * 1000, httpOnly: true});

                return res.status(response.statusCode).send(body);
			   //return res.json(body);
			}).catch(function(e){
				res.json(e);
			})
		}else{
			res.json({code:500,msg:"不支持的请求类型"});
		}
	})
	return router;
};

  

  

index.js

var express = require('express');
var router = require("./routers");


var cors = require('cors');

var app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());


var config = {
	target:"http://xxxxxx"
};

app.use("/",router(config));

app.listen("3000",function(error){
	console.log("启动服务-----3000");
})

  

 

 

 

koa2 版本

const router = require('koa-router')()

var request = require("request");
/* GET home page. */



const Api = {
	GET(params){
		params = params || {};
		return new Promise(function(resolve,reject){
			request({
				method:"GET",
				url:params.url,
				qs:params.data
			},function (error, response, body) {
			    if (!error && response.statusCode == 200) {
			        try{
						body = JSON.parse(body);
					} catch(e){
						
					}
					resolve(body);
			    }else{
					reject(error);
			    }
			});
		})
		
	},
	POST(params){
		params = params || {};
		return new Promise(function(resolve,reject){
			request({
				method:"POST",
				url:params.url,
				form:params.data
			},function (error, response, body) {
			    if (!error && response.statusCode == 200) {
			        try{
						body = JSON.parse(body);
					} catch(e){
						
					}
					resolve(body);
			    }else{
					reject(error);
			    }
			});
		})
	}
}

module.exports = function(opt){
	opt  = opt || {};
	var target = opt.target || '';
	var url = opt.url || "**";
	if(opt.prefix){
		router.prefix(opt.prefix)
	}
	router.all(url,async function(ctx,next){
		var url = target  + ctx.path;
	
		var data = {};
		if(ctx.method =="GET"){
			data = ctx.query;
		}else if(ctx.method == "POST"){
			data = ctx.request.body;
		}
		console.log("请求来源:"+url,data,ctx.method);
		if(Api[ctx.method]){
			try{
			ctx.body =	await Api[ctx.method]({
					url:url,
					data:data
				});
			}catch(e){
				ctx.body = e;
			}
		
		}else{
			ctx.body = {code:500,msg:"不支持的请求类型"};
		}
	})
	return router;
};

  

 

使用:

const proxy = require('./routers');

const insproxy = proxy({
  target:"xxxx",
  prefix:"/xxx"
});

app.use(insproxy.routes(), insproxy.allowedMethods());