NodeJS — Как создать и прочитать сеанс с помощью express

#node.js

#node.js

Вопрос:

Я хочу создать сеанс пользователя, когда пользователь входит в приложение. И читать сеанс всякий раз, когда это необходимо. Вот моя попытка

 var io   = require('socket.io'),
    express = require('express');
    querystring = require('querystring');

var app = express.createServer();
app.get('/', function(req, res){
    var sessionVal = querystring.parse(req.url.substr(2));// sessionVal is an email for example: me@gmail.com
    app.use(express.cookieParser());
    app.use(express.session({ secret: sessionVal }));
});
var socket = io.listen(app);
socket.on('connection', function(client) {
    client.on('message', function(message) {
        // message will be an object {text:'user text chat blah blah', email:'me@gmail.com'}
        // if the seesion stored, has the same value with message.email
        // then the message will be broadcasted
            socket.broadcast(message.text);
        // else will not broadcast  
    });
});

app.listen(4000);
  

Ответ №1:

Я должен указать здесь, что вы неправильно добавляете промежуточное программное обеспечение в приложение. app.use Вызовы должны выполняться не внутри app.get обработчика запроса, а вне его. Просто вызовите их непосредственно после createServer или взгляните на другие примеры в документах.

Секрет, который вы передаете express.session , должен быть строковой константой или, возможно, чем-то, взятым из файла конфигурации. Не передавайте ему то, что клиент может знать, это на самом деле опасно. Это секрет, о котором должен знать только сервер.

Если вы хотите сохранить адрес электронной почты в сеансе, просто сделайте что-нибудь вроде:

 req.session.email = req.param('email');
  

С этим покончено…


Если я правильно понимаю, что вы пытаетесь сделать, это обработать один или несколько HTTP-запросов и отслеживать сеанс, а затем позже открыть сокет.Соединение ввода-вывода, из которого вам также нужны данные сеанса.

Что сложно в этой проблеме, так это сокет.Способ ввода-вывода заставить волшебство работать с любым http.Server — перехватить request событие. Таким образом, промежуточное программное обеспечение сеанса Express (или, скорее, промежуточное программное обеспечение Connect) никогда не вызывается в сокете.Подключение к IO.

Я верю, что вы можете заставить это работать, правда, с некоторыми хитростями.

Вы можете получить доступ к данным сеанса подключения; вам просто нужно получить ссылку на хранилище сеансов. Самый простой способ сделать это — создать хранилище самостоятельно перед вызовом express.session :

 // A MemoryStore is the default, but you probably want something
// more robust for production use.
var store = new express.session.MemoryStore;
app.use(express.session({ secret: 'whatever', store: store }));
  

У каждого хранилища сеансов есть get(sid, callback) метод. sid Параметр, или идентификатор сеанса, хранится в файле cookie на клиенте. Имя этого файла cookie по умолчанию — connect.sid . (Но вы можете присвоить ему любое имя, указав key опцию в вашем express.session вызове.)

Затем вам нужно получить доступ к этому файлу cookie в сокете.Подключение к IO. К сожалению, сокет.Ввод-вывод, похоже, не дает вам доступа к http.ServerRequest . Простым решением было бы извлечь файл cookie в браузере и отправить его через сокет.Подключение к IO.

Код на сервере тогда выглядел бы примерно следующим образом:

 var io      = require('socket.io'),
    express = require('express');

var app    = express.createServer(),
    socket = io.listen(app),
    store  = new express.session.MemoryStore;
app.use(express.cookieParser());
app.use(express.session({ secret: 'something', store: store }));

app.get('/', function(req, res) {
  var old = req.session.email;
  req.session.email = req.param('email');

  res.header('Content-Type', 'text/plain');
  res.send("Email was '"   old   "', now is '"   req.session.email   "'.");
});

socket.on('connection', function(client) {
  // We declare that the first message contains the SID.
  // This is where we handle the first message.
  client.once('message', function(sid) {
    store.get(sid, function(err, session) {
      if (err || !session) {
        // Do some error handling, bail.
        return;
      }

      // Any messages following are your chat messages.
      client.on('message', function(message) {
        if (message.email === session.email) {
          socket.broadcast(message.text);
        }
      });
    });
  });
});

app.listen(4000);
  

Предполагается, что вы хотите прочитать только существующий сеанс. На самом деле вы не можете создавать или удалять сеансы, потому что Socket.Соединения ввода-вывода могут не иметь HTTP-ответа для отправки Set-Cookie заголовка (например, WebSockets).

Если вы хотите редактировать сеансы, это может работать с некоторыми хранилищами сеансов. Например, CookieStore не будет работать, потому что ему также необходимо отправить Set-Cookie заголовок, чего он не может. Но для других хранилищ вы могли бы попробовать вызвать set(sid, data, callback) метод и посмотреть, что получится.

Комментарии:

1. спасибо за каждое подробное объяснение, я использую req.session.email = req.param(‘электронная почта’); Как я могу получить доступ к сохраненному значению электронной почты?

2. Я забыл сообщить об ошибке, когда я использую req.session.email = req.param(’email’), ошибка сервера гласит, что не удается установить для свойства email значение undefined.

3. Я все еще считаю, что вы неправильно используете промежуточное программное обеспечение. При правильном выполнении у вас должно получиться req.session . Как я показал в примере, вы можете получить доступ к сохраненной электронной почте с помощью req.session.email .

4. Я добавил более полный пример. Этот код выполняется, и у меня работает связанный с сеансом код для GET / обработчика. На самом деле я не тестировал код сокета, но считаю, что он должен работать.

5. Похоже, что для файла cookie по умолчанию установлено значение HttpOnly. express.session также требуется cookie опция. Взгляните на: senchalabs.github.com/connect/middleware-session.html

Ответ №2:

Я забыл сообщить об ошибке, когда я использую req.session.email = req.param(’email’), ошибка сервера гласит, что не удается установить для свойства email значение undefined.

Причиной этой ошибки является неправильный порядок app.use. Вы должны настроить express в таком порядке:

 app.use(express.cookieParser());
app.use(express.session({ secret: sessionVal }));
app.use(app.route);
  

Ответ №3:

Взаимодействие с сокетом является громоздким.поддержка сеансов ввода-вывода и подключения. Проблема не в том, что сокет.io каким-то образом «перехватывает» запрос, но из-за определенного сокета.средства ввода-вывода (я думаю, что flashsockets) не поддерживают файлы cookie. Я мог ошибаться с файлами cookie, но мой подход заключается в следующем:

  1. Внедрите отдельное хранилище сеансов для сокета.ввод-вывод, который хранит данные в том же формате, что и connect-redis
  2. Сделайте cookie сеанса подключения не только http, чтобы он был доступен из клиентского JS
  3. После сокета.подключение к io, отправка cookie сеанса через сокет.ввод-вывод из браузера на сервер
  4. Сохраните идентификатор сеанса в сокете.подключение к io и использовать его для доступа к данным сеанса из redis.

Ответ №4:

Шаги, которые я сделал:

  1. Включите angular-cookies.js файл в формате HTML!
  2. Инициализировать файлы cookie как НЕ доступные только для http в серверном приложении.s:

     app.configure(function(){
       //a bunch of stuff
       app.use(express.cookieSession({secret: 'mySecret', store: store, cookie: cookieSettings}));```
      
  3. Затем в клиентских службах.jss я вставил [‘ngCookies’] вот так:

    angular.module('swrp', ['ngCookies']).//etc

  4. Затем в controller.js , в моей функции UserLoginCtrl , у меня есть $cookies там с $scope вверху вот так:

    function UserLoginCtrl($scope, $cookies, socket) {

  5. Наконец, чтобы получить значение cookie внутри функции контроллера, я сделал:

    var mySession = $cookies['connect.sess'];

Теперь вы можете отправить это обратно на сервер с клиента. Потрясающе. Жаль, что они не поместили это в Angular.js документация. Я понял это, просто прочитав фактический код для angular-cookies.js напрямую.

Ответ №5:

Здравствуйте, я пытаюсь добавить новые значения сеанса в node js, например

 req.session.portal = false
Passport.authenticate('facebook', (req, res, next) => {
    next()
})(req, res, next)
  

В passport strategies я не получаю значение портала в запросе Mozilla, но отлично работаю с Chrome и opera

 FacebookStrategy: new PassportFacebook.Strategy({
    clientID: Configuration.SocialChannel.Facebook.AppId,
    clientSecret: Configuration.SocialChannel.Facebook.AppSecret,
    callbackURL: Configuration.SocialChannel.Facebook.CallbackURL,
    profileFields: Configuration.SocialChannel.Facebook.Fields,
    scope: Configuration.SocialChannel.Facebook.Scope,
    passReqToCallback: true
}, (req, accessToken, refreshToken, profile, done) => {
    console.log(JSON.stringify(req.session));