鍍金池/ 問答/Linux  HTML/ express-session在客戶端不能保存connnect_sid

express-session在客戶端不能保存connnect_sid

express環(huán)境下開發(fā)的登錄驗證碼,將驗證碼存入session中,發(fā)現(xiàn)客戶端并沒有能夠成功在cookie中保存connnect_sid,后端跑在3000端口,前端用ng4+ng-zorro跑在4200,代碼片段如下:
app.js:

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// nginx反向代理時獲取正確的客戶端ip
app.set('trust proxy', 'loopback');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, X-Access-Token, X-Real-IP');
  res.header('Access-Control-Allow-Methods','PUT,POST,GET,DELETE,OPTIONS');
  next();
});

app.use(session({
  name: 'nsid',
  secret: 'amazing',
  resave: true,
  saveUninitialized: false,
  rolling: true,
  captcha: 'ss'
}));

// app.use('/', index);

app.use('/api', require('./api/login'));

login.js:

/* 登錄登出接口,驗證碼生成 */
var express = require('express');
var router = express.Router();
const db = require('../config/db');
var svgCaptcha = require('svg-captcha');
var lang = require('../lib/lang.json');

router.route('/user/login')
  .post (function (req, res) {
    var name = req.body.username;
    var pwd = req.body.password;
    var captcha = req.body.captcha;
    console.log(typeof captcha, typeof req.session.captcha);
    console.log(captcha != req.session.captcha);
    if (captcha !== '' && captcha != req.session.captcha) {
      return res.status(200).json({
        status: 0,
        message: `${lang.error},驗證碼錯誤`
      })
    }
    var uInfo = db.get('user').find({name: name}).value();

    if (uInfo) {
      if (name === uInfo.name && pwd === uInfo.pwd) {
        return res.status(200).json({
          status: 1,
          message: lang.success
        })
      } else {
        return res.status(200).json({
          status: 0,
          message: `${lang.error},用戶名或密碼錯誤`
        })
      }
    } else {
      return res.status(200).json({
        status: 0,
        message: `${lang.error},用戶名不存在`
      })
    }
  });

router.route('/captcha')
  .get (function (req, res) {
    var captcha = svgCaptcha.createMathExpr({
      noise: 2,
      color: true,
      width: 116,
      height: 32,
      fontSize: 36,
      background: '#f8f8f8'
    });
    req.session.captcha = captcha.text;
    // console.log(req.session.captcha);

    res.type('svg');
    console.log(req.session.captcha);
    return res.status(200).json({
      status: 1,
      message: lang.success,
      data: captcha.data,
    });
});
router.route('/test')
  .get(function (req, res) {
    console.log(req.session.captcha);
    return res.status(200).json({
      status: 1,
      message: lang.success,
      data: req.session.captcha,
    });
  });

module.exports = router;

存和取兩個請求得到的響應頭如下,由于存的操作沒有成功寫入客戶端的cookie,導致取出的session為undefined:

圖片描述
圖片描述

訪問captcha接口后,客戶端的cookie如下:

圖片描述

會有哪些原因導致客戶端不能保存session的id?

回答
編輯回答
失魂人

根據(jù)查閱到的資料,我發(fā)現(xiàn)問題并沒有出在后端,而是出來前端的angular上。
在發(fā)送http請求時,需要配置一個選項:

  /* 獲取驗證碼 */
  getCaptcha(): Observable<any> {
    const url = `${Config.apiRoot}captcha`;
    const options = new RequestOptions({
      withCredentials: true
    });
    return this.http.get(url, options)
      .map(this.extraData)
      .catch(this.handleError);
  }
  

配置withCredentials: true來允許客戶端在跨域請求時允許setcookie響應頭。

此外,服務器端需要配置中間件:

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'http://localhost:4200'); // 跨域的源
  res.header('Access-Control-Allow-Headers', 'Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, X-Access-Token, X-Real-IP');
  res.header('Access-Control-Allow-Methods','PUT,POST,GET,DELETE,OPTIONS');
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

這樣能夠解決跨域請求時,setcookie響應頭無效/被忽略的問題。

2017年10月27日 01:55