β

vue2+express前后端分离跨域session等问题

行者无疆 108 阅读

基于 vue2 + express 的 RBAC 角色权限验证前后端分离项目。前端vue2 负责路由控制,数据渲染,后端 express 负责数据库操作,RBAC权限控制。

前端:

后端

结构整合

  1. 使用 vue-cli 生成的项目,默认安装了简易的 express,该 express 的启动文件为 build/dev-server.js 。执行 cnpm start 启动该 express,实际主要是启一个服务来运行 Vue。所以我们后端部分不以该文件为入口。
  2. 后端部分的目录使用 express-generator 来生成,由于我们做了前后端分离,所以express 的任务只是提供接口,做数据库操作,所以我们把view、pubic目录删掉。
  3. 最后将前后端代码整合一下。在 vue-cli 生成的目录下创建 server 目录用来存放后端代码,将package.json文件合并,然后添加启动后端的脚本 "server": "node server/bin/www"

package.json 文件如下:

{
  "name": "backend",
  "version": "1.0.0",
  "description": "backend build by webpack+vue2+express",
  "author": "ludis <service@ldsun.com>",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js",
    "lint": "eslint --ext .js,.vue src",
    "server": "node server/bin/www"
  },
  "dependencies": {
    "axios": "^0.16.1",
    "iview": "^2.0.0-rc.15",
    "moment": "^2.18.1",
    "monk": "^5.0.2",
    "vue": "^2.3.3",
    "vue-awesome": "^2.3.1",
    "vue-axios": "^2.0.2",
    "vue-router": "^2.3.1",
    "vuex": "^2.3.1",
    "async": "^2.1.4",
    "cors": "^2.8.3",
    "body-parser": "~1.15.1",
    "cookie-parser": "~1.4.3",
    "debug": "~2.2.0",
    "express": "~4.13.4",
    "express-session": "latest",
    "formidable": "^1.1.1",
    "morgan": "~1.7.0"
  },
  "devDependencies": {
    "autoprefixer": "^6.7.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chalk": "^1.1.3",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-friendly-formatter": "^2.0.7",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^2.0.0",
    "eslint-config-standard": "^6.2.1",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^2.0.1",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^2.0.0",
    "file-loader": "^0.11.1",
    "friendly-errors-webpack-plugin": "^1.1.3",
    "html-webpack-plugin": "^2.28.0",
    "http-proxy-middleware": "^0.17.3",
    "webpack-bundle-analyzer": "^2.2.1",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "opn": "^4.0.2",
    "optimize-css-assets-webpack-plugin": "^1.3.0",
    "ora": "^1.2.0",
    "rimraf": "^2.6.0",
    "url-loader": "^0.5.8",
    "vue-loader": "^12.1.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.3.3",
    "webpack": "^2.6.1",
    "webpack-dev-middleware": "^1.10.0",
    "webpack-hot-middleware": "^2.18.0",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

这样,我们在执行 cnpm start cnpm run server 后即可分别启动前端和后端服务。项目目录如下:

.
├── README.md
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── dev-client.js
│   ├── dev-server.js
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── config
│   ├── dev.env.js
│   ├── index.js
│   └── prod.env.js
├── index.html
├── mongo.json
├── node_modules
├── package.json
├── server  // 后端代码
│   ├── app.js
│   ├── bin
│   ├── lib
│   ├── routes
│   └── service
├── src
│   ├── App.vue
│   ├── assets
│   ├── components
│   ├── main.js
│   └── router
└── static

这样项目的结构比较清晰。 遇到的问题:

const cors = require('cors');  
app.use(cors({  
    origin:['http://localhost:8080'],
    methods:['GET','POST'],
}));

这样就解决了跨域请求问题。

const session = require('express-session');  
const redisStore = require('connect-redis')(session);  
app.use(session({  
    secret: 'backend123...',
    name: 'backend',
    store: new RedisStore(options),
    cookie: {
        maxAge: 1000 * 60 * 60,
    },// 1h
    resave: true,
    saveUninitialized: false,
}));
// 登录
app.post('/login', function(req, res, next){  
    ...
    // 登录成功,拿到用户信息,设置session
    req.session.user = userinfo
})
// 有其他请求时判断登陆
app.user('*', function(req, res, next){  
    if(req.session.user)next() // 如果session存在,是登录状态
    else .... // 未登录
})

但是通过调试发现,每次登陆后用户信息确实存到session中了,但是下次请求时session却为空!最后发现是由于跨域问题引起的。由于使用了cros安全代理,默认是拒绝接收浏览器发送的cookie,所以每次请求都不带cookie,sessionID自然对不上,所以每次都会是新的session,导致没法保存登陆状态。给cors配置参数,允许接收cookie即可。

app.use(cors({  
    origin:['http://localhost:8080'],
    methods:['GET','POST'],
    credentials: true
}));

但是加完了发现问题还是没有解决,那么就是 axios 的问题了,原来axios默认发送http请求时是不会在头信息中附带cookie的,所以也需要配置开启。直接在main.js中全局设置:

import axios from 'axios'    // axios  
import VueAxios from 'vue-axios'  
axios.defaults.withCredentials = true    // 请求携带cookie信息  
Vue.use(VueAxios, axios)  

这样,问题终于解决了233...心累。 坑先填到这,持续更新。

github: https://github.com/flute/webpack vue2 express mongodb backend

参考资料: http://www.ruanyifeng.com/blog/2016/04/cors.html

作者:行者无疆
Welcome to blog
原文地址:vue2+express前后端分离跨域session等问题, 感谢原作者分享。

发表评论