Svelte Sapper保留会话以刷新页面重新加载

问题描述

我最近刚刚开始使用module.exports = { pathPrefix: '/stfuandclick',// ... } "deploy": "gatsby build --prefix-paths && gh-pages -d public" ,即使用户刷新页面,我也试图保持存储的会话。 (我希望可以做到)。

这个想法是,用户可以登录,并以经过身份验证的方式重定向首页。 但是,当我在浏览器中单击“刷新”时,会话为空,用户必须再次进行登录过程。

有什么想法吗?

到目前为止,我找不到解决方案。此过程涉及一些文件下面。

svelte

sapper

server.js

import sirv from "sirv";
import polka from "polka";
import compression from "compression";
import * as sapper from "@sapper/server";
import bodyParser from "body-parser";
import session from "express-session";
import sessionFileStore from "session-file-store";

const { PORT,NODE_ENV } = process.env;
const dev = NODE_ENV === "development";
const FileStore = sessionFileStore(session);

polka()
  .use(
    bodyParser.json(),session({
      secret: "secret",resave: false,saveUninitialized: true,cookie: {
        maxAge: 31536000,},store: new FileStore({
        path: process.env.Now ? `/tmp/sessions` : `.sessions`,}),})
  )
  .use(
    compression({ threshold: 0 }),sirv("static",{ dev }),sapper.middleware({
      session: (req) => ({
        user: req.session && req.session.user,})
  )
  .listen(PORT,(err) => {
    if (err) console.log("error",err);
  });

login.svelte

<script context="module">
  export async function preload({ params },{ user }) {
    if (user) {
      this.redirect(302,`/`);
    }
  }
</script>

<script>
  import { goto,stores } from "@sapper/app";
  import api from "../api.js";
  import Button from "../components/Button.svelte";
  import Input from "../components/Input.svelte";
  import InputPassword from "../components/InputPassword.svelte";

  let errors;
  let email;
  let password;
  let disabled;

  const { session } = stores();

  const handleSubmit = async () => {
    try {
      errors = null;
      disabled = true;
      await api.get("/csrf-cookie");
      const authToken = await api.post("/login",{ email,password });
      api.defaults.headers.common["Authorization"] = `Bearer ${authToken.data}`;
      const user = await api.get("/me");
      session.set({ user: user.data });
      disabled = false;
      goto("/");
    } catch (e) {
      errors = e;
      disabled = false;
    }
  };
</script>

<style>
  .login-form {
    max-width: 35em;
    margin: 5% auto;
    padding: 2em;
    background: rgba(233,233,0.5);
    border: 1px solid rgba(151,151,0.5);
    border-radius: 5px;
  }

  .form-title {
    margin-top: 0;
    font-size: 1.2em;
  }

  .error-block {
    color: red;
  }
</style>

<svelte:head>
  <title>Login</title>
</svelte:head>

<div class="login-form">
  <h3 class="form-title">Login</h3>
  <form on:submit|preventDefault={handleSubmit}>
    <Input placeholder="Username" id="email" bind:value={email} />
    <InputPassword placeholder="Password" id="password" bind:value={password} />
    <Button {disabled} type="submit">Login</Button>

    {#if errors}<span class="error-block">{errors}</span>{/if}
  </form>
</div>

我使用index.svelte进行身份验证。

不知道我还需要提供什么来解决这个问题。

解决方法

似乎您从sapper realworld项目中提取了大部分代码(如果我错了,请纠正我),但是您忘记了实现服务器端的“ api路由”来添加新登录的代码用户参加会话。

在真实世界的项目中,当用户登录时,将向服务器端/auth/login路由发出POST请求,该路由由以下功能提供服务:

import * as api from 'api.js';

export function post(req,res) {
    const user = req.body;

    api.post('users/login',{ user }).then(response => {
        if (response.user) req.session.user = response.user;
        res.setHeader('Content-Type','application/json');

        res.end(JSON.stringify(response));
    });
}

此功能的作用是:

  1. 它将请求转发到realworld project API/users/login端点
  2. 如果对该请求的响应包含一个user对象,则会将该对象存储到服务器端会话中
  3. 它将原始API响应作为JSON返回给应用程序,用于在其中填充会话存储(如果原始响应包含用户对象)

考虑到您显然使用真实世界的项目API进行身份验证,但是您自己的身份验证过程中,您需要添加的是与上述类似的服务器端路由,但是将会:

  • 将登录请求中继到您自己的进程中,
  • 填写响应并使用该响应设置会话用户,
  • 最后将响应传递给客户端(或者,将存储的用户对象传递给会话,否则传递错误消息)。

考虑到您用于在代码的 client 端设置用户的API调用,该函数看起来像这样(例如,将该文件另存为/routes/auth/login.js) :

import * as api from 'api.js';

export async function post(req,res) {
    const { email,password } = req.body;
    const authToken = await api.post("/login",{ email,password });
    api.defaults.headers.common["Authorization"] = `Bearer ${authToken.data}`;
    const user = await api.get("/me");
    if (user) req.session.user = user.data;
    res.setHeader('Content-Type','application/json');
    res.end(JSON.stringify(user));
}

,并且handleSubmit文件中的login.svelte方法变为:

  const handleSubmit = async () => {
    try {
      errors = null;
      disabled = true;
      // substitute your auth API request chain with a proxy request to
      // the server-side API where you will set the server-side session user
      const user = await fetch('/auth/login',{
        method: 'POST',credentials: 'include',body: JSON.stringify({ email,password }),headers: { 'Content-Type': 'application/json' },})
      session.set({ user: user.data });
      disabled = false;
      goto("/");
    } catch (e) {
      errors = e;
      disabled = false;
    }
  };

请注意,在您的特定情况下,您可能还希望将auth令牌存储在会话中,以避免每次想对数据API进行身份验证的请求时都必须请求新的令牌。

,

使用精简的localStorage:

创建商店,例如myStore.js

import { writable } from 'svelte/store';

export let mystore = writable({
    session: ""
});


export function setSession(session) {
    mystore.set({
        session: session
    });
    session = session; // refresh UI
}

在routes / _layout.svelte中订阅

<script>
    import {mystore,setSession} from './myStore.js'

    let session = setSession("A_SESSION"); // here comes the session


    const unsubscribeMyStore = mystore.subscribe(value => {
        session = session;
    });
</script>

<A_COMPONENT bind:session={mystore}/> // if the component exports session

在A_COMPONENT中使用:

<script>
    export let session;
</script>

<div>
{session.session}
</div>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...