vue本地开发之Node搭建代理服务器访问线上API
2018-02-09 00:03

vue实际开发中的服务器问题

如果你是一个vue的开发人员,而且后台是使用的java,php,asp等语言开发的话,那么我们在使用webpack+vue进行开发的时候,在本地开发,往往需要调用后台提供的ajax访问的API接口,这时候,我们就需要在node服务器端模拟后台返回的json文件,返回约定好的数据。这就是前后端分离。而实际过程中,前端的开发效率往往要比后台的开发效率慢,不论是java还是php,我们所需要的接口可能只是一个CRUD(增删查改)而已,后台使用框架,很可能半天甚至两三个小时就搞定了;然后于此同时,前端所等待的设计甚至都还没有完成设计稿,等到前端可以开发的时候,后台API在线上,或者测试服务器上已经可以访问了,这时候我们就没有必要再在node端进行json数据模拟了,完全可以通过node在本地访问线上的API资源,开发完成后,都省去了前后端联调的问题。

Node端使用express搭建服务器

node端也有我们自己的MVC模式的web服务器框架-express,通过express我们可以快速的搭建一个node端的web服务器,而express简单易学,一个小时就完全可以熟练运用,下面我们看一下通过express如何搭建可以访问线上API的服务器。

const express = require('express');
const http=require('http');
app.use(function(req,res,next){
	if(req.path.indexOf("/static/json")!=-1){
		console.log("本地静态json文件");
		next();
	}else{
		http.get('http://20.20.212.xxx'+req.path,function(hres){
			var html='';
			hres.on('data',function(data){
				html+=data;
			});
			hres.on('end',function(data){
				res.send(html);
			});
		});
	}
});
app.use('/static/json/:name',function(req,res){
	var filepath=__dirname+'/json/'+req.params.name;
	console.log(req.params.name);
	var filename=req.params.name;
	if(!fs.existsSync(filepath)){
		filename='norst.json';
	}
	res.sendFile(filename,{root:__dirname+'/json'},err=>{
		if(err){
			console.log("请求json数据失败!");
			console.log(err);
		}else{
			console.log(req.params.name+'.json文件数据已经发送成功!');
		}
	});

});
app.listen(80,function(err){
	console.log('web Server Listen on 80 port...');
});

上面的代码通过node运行后,我们就启动了一个web服务器,这个node访问线上的资源的原理是这样的:

在vue中我们通过axios访问一个API接口:

Axios.get("http://www.baidu.com/getWeather").then(res=>{
	store.commit("uprst",res.data.data);
});

本地代码中,我们直接访问的是线上的域名、接口,这在浏览器中是会因为跨域问题访问不到的,但是我们可以做一个变通,那就是根据浏览器访问资源的原理:

    浏览器在输入url地址后,会先去电脑上hosts文件中查找是否有相应的记录,如果有,那么就直接根据hosts文件中的记录访问对应的IP地址,如果hosts中没有记录,才会进一步去域名服务器进行域名翻译ip地址。

hosts文件的路径为:C:\Windows\System32\drivers\etc(windows操作系统),

hosts文件的内容如下:

image.png

其中,前面带#号的是注释内容,在上面的hosts文件中,这台电脑访问百度时,会跳到182.125.23.26这么个ip地址上,当然这是访问不到任何内容的,因为这是我瞎填的。

而根据这个原理,我们把要访问的API接口在hosts文件中修改未127.0.0.1,这样的话,我们实际访问的就是本地的node服务器,node服务器再根据这个域名真是的IP地址发起http请求获取数据,然后返回,这样我们就可以访问线上的API接口了。

更进一步的做法就是,我们在vue代码中通过相对路径访问,这样我们就不用修改hosts文件了,直接访问的是node服务器,node服务器再在访问路径前面加上线上的域名请求数据。

其实现在好多服务器禁止了IP访问,目的是为了规避一些IP引起的攻击。对于这类服务器,我们就可以通过使用相对路径的方式进行访问。


如果你对相对路径,绝对路径比较迷糊,那么你可以这么办,在你的vue代码全局中设置:

//本地在局域网中的IP
const baseUrl="http://192.168.32.75/";
//线上的域名
//const baseUrl="http://baidu.com;

请求的地址可以这样写:

Axios.get(baseUrl+"/getWeather/").then(res=>{
	store.commit("uprst",res.data.data);
});

这样的话,在node服务器获取路径,再前面加上线上域名,请求数据再返回。只是这种方式,开发的时候我们使用本地的ip地址,在部署打包时,我们要切换成线上的baseUrl。


上面的node服务器代码,我们还有一段是访问本地的静态资源,如json文件

app.use('/static/json/:name',function(req,res){
	var filepath=__dirname+'/json/'+req.params.name;
	console.log(req.params.name);
	var filename=req.params.name;
	if(!fs.existsSync(filepath)){
		filename='norst.json';
	}
	res.sendFile(filename,{root:__dirname+'/json'},err=>{
		if(err){
			console.log("请求json数据失败!");
			console.log(err);
		}else{
			console.log(req.params.name+'.json文件数据已经发送成功!');
		}
	});

});

而在代理代码里面,我们做了判断来过滤本地的静态资源:

if(req.path.indexOf("/static/json")!=-1){
	console.log("本地静态json文件");
	next();
}

这样,对于线上的接口我们可以访问到,对于本地的静态json数据,我们也可以访问到了。

node服务器结合webpack

而现在我们开发vue的时候大多数使用的自动化工具是webpack,上面的express服务器需要跟我们的webpack结合才能使用,恰巧,webpack也提供了这类的express的中间件,我们可以向下面这样就能结合webpack了。

const webpack = require('webpack'),
	  webpackDevMiddle = require('webpack-dev-middleware'),
	  webpackHotMiddle = require('webpack-hot-middleware'),
	  webpackConfig	= require('./webpack.config.js'),
	  express = require('express');
const http=require('http');

var fs=require('fs');

let compiler=webpack(webpackConfig);

let app=express();

app.use(webpackDevMiddle(compiler,{
	publicPath:webpackConfig.output.publicPath,
	stats: {
        colors: true
    }
}));
app.use(webpackHotMiddle(compiler));

结合完webpack,后面再加上我们自己的代理访问和静态资源访问代码,就可以愉快的开发了。

完整的express+webapck的代理服务器可以是下面这样的:

const webpack = require('webpack'),
	  webpackDevMiddle = require('webpack-dev-middleware'),
	  webpackHotMiddle = require('webpack-hot-middleware'),
	  webpackConfig	= require('./webpack.config.js'),
	  express = require('express');
const http=require('http');
var fs=require('fs');

let compiler=webpack(webpackConfig);

let app=express();

app.use(webpackDevMiddle(compiler,{
	publicPath:webpackConfig.output.publicPath,
	stats: {
        colors: true
    }
}));
app.use(webpackHotMiddle(compiler));

app.use(function(req,res,next){
	if(req.path.indexOf("/static/json")!=-1){
		console.log("静态json文件");
		next();
	}else{
		http.get('http://www.baidu.com/'+req.path,function(hres){
			var html='';
			hres.on('data',function(data){
				html+=data;
			});
			hres.on('end',function(data){
				res.send(html);
			});
		});
	}
});

app.use('/static/json/:name',function(req,res){
	var filepath=__dirname+'/json/'+req.params.name;
	console.log(req.params.name);
	var filename=req.params.name;
	if(!fs.existsSync(filepath)){
		filename='norst.json';
	}
	res.sendFile(filename,{root:__dirname+'/json'},err=>{
		if(err){
			console.log("请求json数据失败!");
			console.log(err);
		}else{
			console.log(req.params.name+'.json文件数据已经发送成功!');
		}
	});

});
app.listen(80,function(err){
	console.log('web Server Listen on 80 port...');
});

而对应的webpack代码,类似下面这种,我们需要多添加一个webpack-hot-middleware/client?reload=true这么一个js路径作为热加载的功能启用。

const webpack=require('webpack');
const path=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
const ExtractTextPlugin=require('extract-text-webpack-plugin');
var hotMiddlewareScript = 'webpack-hot-middleware/client?reload=true';

process.env.NODE_ENV='mbbtn-cont';
//区分开发坏境和正式环境
var NODE_ENV = process.env.NODE_ENV || 'mbbtn-cont';
var isDev = NODE_ENV === 'development';
var entry;
if(isDev){
	entry={
		'js':['./src/main.js',hotMiddlewareScript]
	};
}else{
	entry={
		'js':'./src/main.js'
	}
}

var config={
	entry:entry,
	output:{
		path:path.resolve(__dirname,'dest'),
		filename:'static/[name]/bd_[hash].bundle.js',
		publicPath:'/'
	},
	resolve:{
		extensions:['.js','.vue','.json'],
		/*alias:{
			'vue$':'vue/dist/vue.esm.js',
			'axios$':'axios/dist/axios.min.js'
		}*/
	},
	module:{
		rules:[
			{
			    test:/\.(png|jpg|gif)$/,
			    use:'file-loader?name=static/images/bd_[name]_[hash].[ext]'
			},
			{
			    test:/\.css$/,
			    //抽离css代码
			    use:['css-hot-loader'].concat(ExtractTextPlugin.extract({
				    fallback:'style-loader',
				    use:'css-loader'
			    }))
			},
			{
			    test:/\.vue$/,
			    use:'vue-loader?name=static/components/[name].[ext]'
			},
			{
			    test:/\.js$/,
			    exclude: /(node_modules|bower_components)/,
			    use:{
				    loader:'babel-loader',
				    options:{
					    presets:[ "env", "stage-2"]
				    }
			    }
			}
		]
	},
	plugins:[
		new HtmlWebpackPlugin({
			template:'./src/template/index.html',
			title:'工具'
		}),
		//抽离css代码
		new ExtractTextPlugin('static/css/bd_individual.css'),
		/*new webpack.optimize.OccurenceOrderPlugin(),*/
		new webpack.HotModuleReplacementPlugin(),
		/*new webpack.optimize.CommonsChunkPlugin({
			name:'manifest'
		})
*/	],
        //在index.html中引入cdn的vue资源
	externals:{
		vue:"Vue",
		axios:"axios",
		vuex:"Vuex",
		"vue-router":"VueRouter"
	}
}

module.exports=config;

这段webpack配置中用到了babel,而在vue中我写ES6的解析析构写法是报错的(...mapState(),...mapGetters()这种写法),所以就弄了一个 .babelrc文件来写babel的配置,而将这段配置写到babel的options选项中竟然不管用,暂时没弄明白原因,先把.babelrc的内容贴出来:

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  "plugins": ["transform-vue-jsx", "transform-runtime","syntax-dynamic-import"]
}

好吧,本文到此结束,babel的官网因为是英文的,而我英文水平欠缺,所以有待深入了解。

希望此文能对前端自动化开发中访问线上资源提供一种可行的方案来造福前端开发人员。

如果你需要完全的服务器代理可以使用http-proxy-middleware中间件实现node代理服务器

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(918)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1