Сессия Sapper / svelte3 не синхронизируется без перезагрузки страницы

Мне не удается заставить Sapper синхронизировать изменения сеанса, сделанные в моих серверных маршрутах, без загрузки страницы. Мой пример сценария состоит в том, что я загружаю свое приложение без пользователя в сеансе, мой серверный маршрут входа в систему устанавливает пользователя в сеанс, и я использую goto, чтобы попасть на панель управления.

Проблема в том, что аргумент session в функции предварительной загрузки приборной панели не заполнен. Если я использую window.location.href = '/dashboard', это так, потому что он работает через page_handler. Но если я выполняю перенаправление только для клиента, Sapper не отправляет обновленный сеанс клиенту.

Каким-нибудь образом обойти это? Я неправильно использую свои инструменты?

Примечание: я использую connect-pg-simple и express-session, настраивая sapper следующим образом: sapper.middleware({session: (req, res) => req.session.public}).


person jstaab    schedule 15.08.2019    source источник
comment
Посмотрите: stackoverflow.com/questions/58002360/   -  person Jean-Claude Schmidig    schedule 14.02.2020


Ответы (2)


Я нашел свой ответ в документации Sapper

session содержит все данные, которые были загружены на сервер. Это хранилище с возможностью записи, то есть вы можете обновить его новыми данными (например, после того, как пользователь войдет в систему), и ваше приложение будет обновлено.

Если читать между строк, это означает, что ваше приложение должно вручную синхронизировать данные сеанса.

Решение здесь состоит в том, чтобы вручную синхронизировать данные сеанса с клиентом либо с помощью веб-перехватчика, либо с помощью заголовка ответа, либо с помощью ключа в данных ответа.

У меня есть декоратор, который я использую для создания обработчика маршрута сервера, в котором я добавляю данные сеанса в ответ. Вот упрощенная версия:

const createHandler = getData => (req, res) => {
  res.status(200).json({data: getData(req.body), session: req.session.public})
}

Очевидно, что это еще не все, например обработка ошибок, но идею вы поняли. На клиенте я оборачиваю fetch вспомогательной функцией, которую я всегда использую, чтобы получить свой json, установить правильные заголовки и т. Д. В нем я смотрю на ответ, и если есть свойство session, я устанавливаю его для сеанса store, чтобы он был у меня в preloads.

import {stores} from "@sapper/app"

const myFetch = (...args) => fetch(...args).then(r => r.json()).then(body => {
  if (body.session) stores().session.set(body.session)

  return body.data
})
person jstaab    schedule 15.08.2019
comment
Спасибо за Ваш ответ. Я как бы понимаю ваш ответ, но я не могу заставить свою предварительную загрузку передавать данные. Не возражаете, если вы разместите пример своей preload ‹script context = module› export async function preload () {}, чтобы увидеть, как вы устанавливаете сеанс в store ()? Это большая проблема, и я вижу несколько сообщений с просьбами о помощи, но никто не помогает. Похоже, что здесь ответил только Рич, и нам нужен работающий пример. - person Marco; 10.10.2019
comment
К сожалению, мне не удалось заставить работать предварительную загрузку (сессия была частью проблемы, я думаю, было что-то еще), поэтому у меня нет рабочих примеров. - person jstaab; 11.10.2019
comment
отличный ответ, спасибо - person mtyson; 14.02.2021

Проще говоря, после того, как статус вашего сеанса изменится из внешнего интерфейса (пользователь только что вошел в систему, или вы только что аннулировали его логин), вы должны обновить хранилище сеансов во внешнем интерфейсе.

<script>
  import { goto, stores } from '@sapper/app';
  const { session } = stores();

  const loginBtnHandler = () => {

    const req = await fetch('/api/login', {
      method: 'POST',
      credentials: 'same-origin', // (im using cookies in this example)
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ ........ })
   });

   if (req.ok) {
     // here is where you refresh the session on the client right after you log in
     $session.loggedIn = true; // or your token or whatever

     // next page will properly read the session
     goto('/');

     return;
   }

   ...

  }
</script>
person Alex    schedule 08.01.2021