2

该网站的示例:

import vibe.d;

void login(HTTPServerRequest req, HTTPServerResponse res)
{
    enforceHTTP("username" in req.form && "password" in req.form,
        HTTPStatus.badRequest, "Missing username/password field.");

    // todo: verify user/password here

    auto session = res.startSession();
    session["username"] = req.form["username"];
    session["password"] = req.form["password"];
    res.redirect("/home");
}

void logout(HTTPServerRequest req, HTTPServerResponse res)
{
    res.terminateSession();
    res.redirect("/");
}

void checkLogin(HTTPServerRequest req, HTTPServerResponse res)
{
    // force a redirect to / for unauthenticated users
    if( req.session is null )
        res.redirect("/");
}

shared static this()
{
    auto router = new URLRouter;
    router.get("/", staticTemplate!"index.dl");
    router.post("/login", &login);
    router.post("/logout", &logout);
    // restrict all following routes to authenticated users:
    router.any("*", &checkLogin);
    router.get("/home", staticTemplate!"home.dl");

    auto settings = new HTTPServerSettings;
    settings.sessionStore = new MemorySessionStore;
    // ...
}

但是可以说我不想将整个程序中的 ServerResponse 传递给每个函数。例如,如果 res.session 存储了当前用户的 id 怎么办。这经常使用,所以我不希望它通过每个函数。如何在全球范围内存储此会话信息?假设有多个用户使用该网站。

4

1 回答 1

3

这是可能的,虽然有点气馁。

解决方案

您不能简单地将其存储在全局范围内,因为没有“全局”会话之类的东西 - 它始终特定于请求上下文。即使在 D 中默认设置全局线程本地也无济于事,因为多个纤程共享相同的执行线程。

对于这样的任务,vibe.d 提供了TaskLocal模板,它允许你做你想做的事。我没有尝试过,但希望TaskLocal!Session session“正常工作”。

请注意文档中的这两个警告:

但是请注意,每个 TaskLocal 变量都会增加任何使用任务本地存储的任务的内存占用。访问 TaskLocal 变量也有开销,高于线程局部变量,但通常仍为 O(1)

FiberLocal 实例必须声明为静态/全局线程局部变量。将它们定义为临时/堆栈变量将导致崩溃或数据损坏!

异议

然而,根据我的经验,尽管打字不便,最好还是明确地传递所有这些上下文。不鼓励使用全局变量是有原因的——随着程序大小的增长,不可避免地难以跟踪模块之间的依赖关系并测试此类代码。现在陷入便利的诱惑可能会在以后引起很多头痛。为了尽量减少额外的输入并简化代码维护,我可能会建议改为定义struct Context { ...} 哪些将包含请求/会话指针,并将定期传递。

于 2013-12-10T14:13:38.983 回答