SvelteKitとVaporでSSRした際にCookieがパーセントエンコードされてSessionが動かないのを解決する方法

Last Updated on 2023年8月4日 by lemonade

この記事は、Server-Side SwiftフレームワークVaporとSvelteKitによるSSR(Server-Side Rendering)を使用した際にSvelteKitのSSRでのfetch時にcookieの値がパーセントエンコードされてVaporがそれをsession idが異なると認識するためにsessionが働かなくなるというのを解決するための方法を説明しています。

解決方法

このようなクッキー値をパーセントデコードするミドルウェアを自作します。

import Vapor
import Foundation

struct CookieMiddleware: AsyncMiddleware {
    
    func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
        guard var cookie = request.cookies["vapor-session"] else {
            return try await next.respond(to: request)
        }
        if let decoded = cookie.string.removingPercentEncoding {
            cookie.string = decoded
            request.cookies["vapor-session"] = cookie
        }
        return try await next.respond(to: request)
    }
    
}

configure関数内でsessionミドルウェアを設定する前にこのミドルウェアを設定します。

import NIOSSL
import Fluent
import FluentPostgresDriver
import Vapor

// configures your application
public func configure(_ app: Application) async throws {
    // ...
    app.middleware.use(CookieMiddleware())
    app.middleware.use(app.sessions.middleware)
    // ...
}

問題について

特に述べることはないのですが、Cookieのエンコード方法はRFC6525

To maximize compatibility with user agents, servers that wish to store arbitrary data in a cookie-value SHOULD encode that data, for example, using Base64 [RFC4648].
https://datatracker.ietf.org/doc/html/rfc6265

和訳すると

ユーザーエージェントとの互換性を最大限にするために、サーバーが任意のデータをクッキー値に保存したい場合、そのデータを例えばBase64 [RFC4648]を使用してエンコードするべきです。

とされています。base64でエンコードされるのが多いようですが、明確にエンコード方法は定められていません。

SvelteKitではサーバー内でfetchが実行されるとnode-fetchで、クライアント側で実行される際にはwindow.fetchが使用されるようですが、node-fetchではパーセントエンコードされてしまうのかもしれませんが、サーバーにはパーセントエンコードされたCookieが送られ、sessionをうまく動かすことができません。

Leave a Comment

CAPTCHA