前言
最近在一直在忙着给项目添加node中间层的事情,终于在这个版本正式上线了。关于为什么要做node中间层,这个问题我被问了好多遍,在我看来,其原因有一下几点:
- 避免了跨域的问题
- 使前后端分离更明确,后端负责提供数据,前端只需要注重ui层的效果,部分逻辑都可以迁移到中间层处理
- 也保护了后端接口的域名,启动项目后在浏览器看到的接口都是经过中间层转发的接口
废话不多说,我们看具体实现吧
将node项目和vue项目部署在同一个路由下
创建express项目
这里我们采用express来作为技术框架
新建文件夹nodemiddle
npm init
一路enter下去即可
npm install express
npx express-generator
npm install
按照以上几步,便可完成express项目的初始化了
创建vue项目
就在刚刚新建的nodemiddle文件夹下初始化vue项目
vue create hello-world
将两个项目揉合到一起
安装connect-history-api-fallback中间件
npm install --save connect-history-api-fallback
安装完成之后切换到hello-world目录
npm run build
生成dist文件夹
然后修改app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// ----------------这两行被我们注释掉了-----------
// app.use('/', indexRouter);
// app.use('/users', usersRouter);
//---------------------------------------------
// ----------------这三行是我们新添加的-----------
var history = require('connect-history-api-fallback');
app.use(express.static(path.join(__dirname, './hello-world/dist')));
app.use(history());
//---------------------------------------------
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
切换到根目录,运行项目便可看到效果了
express启动https服务
由于我们项目的原因,本地必须起https服务
检查是否有openssl(一般安装了git就都会有)
openssl version -a
生成证书文件
#1、生成私钥key文件:
openssl genrsa -out privatekey.pem 1024
#2、通过私钥生成CSR证书签名 (需要填一些信息、可直接回车)
openssl req -new -key privatekey.pem -out certrequest.csr
#3、通过私钥和证书签名生成证书文件
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
执行完第三条命令就会有 Signature ok的提示,表示成功了
然后我们修改app.js文件
// 将这一行注释掉
// module.exports = app;
//修改为下面的内容
var options = {
key: fs.readFileSync('./ssl/privatekey.pem'),
cert: fs.readFileSync('./ssl/certificate.pem')
};
https.createServer(options, app).listen(8443, function () {
console.log('Https server listening on port ' + 8443);
});
这个时候我们本地就可以启动https服务了
接口转发实现
由于我们项目中使用到了graphql的接口,这里我就简单实现一下graphql的接口转发 ,由于我一直没有处理好像resetful一样转发,所以这里我就做了一层转化,在express中调用graphql接口,但向vue项目提供的是 resetful接口
首先下载依赖
npm i apollo-fetch
修改app.js
const { createApolloFetch } = require('apollo-fetch');
app.get('/graphql',(request,response) => {
const fetch = createApolloFetch({
uri: 'http://localhost:8080/graphql',
});
fetch({
query: '{ hello}',
}).then(res => {
console.log(res)
})
})
这里提供graphql接口是我简单实现的一个demo,具体参考github.com/huisunyang/…
异常处理
既然转发接口了,那么肯定少不了异常的处理,比较尴尬的是express 没有办法直接处理promise异常,通常都会报错 UnhandledPromiseRejectionWarning
这里我采取的是修改路由组件
const Layer = require('express/lib/router/layer');
Object.defineProperty(Layer.prototype, 'handle', {
enumerable: true,
get() {
return this.__handle;
},
set(fn) {
if (fn.length === 4) {
this.__handle = fn;
} else {
this.__handle = (req, res, next) =>
Promise.resolve()
.then(() => fn(req, res, next))
.catch(next);
}
},
})
加上上面的代码后就可以直接处理异常了
app.get('/test', (request,response)=> {
axios.get('http://localhost:3000/test').then(res => {
response.send(res.data)
}).catch(error => {
response.status(error.response.status).send(error)
})
})
写在最后
以上便是我往vue 项目中添加node中间层所做的处理,后续还在优化中,有不对的地方,还请指出,感谢!!!