#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, но мой подход заключается в следующем:
- Внедрите отдельное хранилище сеансов для сокета.ввод-вывод, который хранит данные в том же формате, что и connect-redis
- Сделайте cookie сеанса подключения не только http, чтобы он был доступен из клиентского JS
- После сокета.подключение к io, отправка cookie сеанса через сокет.ввод-вывод из браузера на сервер
- Сохраните идентификатор сеанса в сокете.подключение к io и использовать его для доступа к данным сеанса из redis.
Ответ №4:
Шаги, которые я сделал:
- Включите angular-cookies.js файл в формате HTML!
-
Инициализировать файлы cookie как НЕ доступные только для http в серверном приложении.s:
app.configure(function(){ //a bunch of stuff app.use(express.cookieSession({secret: 'mySecret', store: store, cookie: cookieSettings}));```
-
Затем в клиентских службах.jss я вставил [‘ngCookies’] вот так:
angular.module('swrp', ['ngCookies']).//etc
-
Затем в
controller.js
, в моей функцииUserLoginCtrl
, у меня есть$cookies
там с$scope
вверху вот так:function UserLoginCtrl($scope, $cookies, socket) {
-
Наконец, чтобы получить значение 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));