vue项目添加node中间层

1,564 阅读3分钟

前言

最近在一直在忙着给项目添加node中间层的事情,终于在这个版本正式上线了。关于为什么要做node中间层,这个问题我被问了好多遍,在我看来,其原因有一下几点:

  • 避免了跨域的问题
  • 使前后端分离更明确,后端负责提供数据,前端只需要注重ui层的效果,部分逻辑都可以迁移到中间层处理
  • 也保护了后端接口的域名,启动项目后在浏览器看到的接口都是经过中间层转发的接口

废话不多说,我们看具体实现吧

项目地址:github.com/huisunyang/…

将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中间层所做的处理,后续还在优化中,有不对的地方,还请指出,感谢!!!