在 HTTP 服务器中共享不可变引用

Share immutable reference in a HTTP Server

我目前正在构建一个 HTTP 服务,用于公开对唯一对象的操作。 我已经创建了中心对象,其中有几种方法采用不可变 &self 引用,并在内部使用各种高效的同步结构来访问内部数据(所有代码都是不安全的)。我的想法是,这足以使其同时使用安全。

然后是将它实际连接到 HTTP 服务器的困难部分。 我目前正在尝试使用 Iron,但我可以切换到 Nickel.rs 或其他任何可以让事情变得更容易的工具。

我看到的大多数 HTTP 服务器示例都使用无状态处理程序,无法访问局部变量。我现在明白为什么了:这几乎是不可能的。

这是我想要使用 Nickel.rs 执行的示例: https://gist.github.com/Gyscos/42510a335098ce935848

这是使用 Iron 的类似失败尝试: https://gist.github.com/Gyscos/92e56e95baee0ebce78f

基本思想是 obj 只在范围内存在,但服务器也是如此,所以应该没什么大不了的......对吧?

不幸的是,我的每一次尝试都失败了。当尝试为服务器提供一个访问 self.object 的闭包时,我收到一条错误消息,指出闭包可能比引用更有效。

我看到Iron提供了一个带有Read结构的共享内存模块。它不仅对我的需求来说看起来过于复杂,我还想避免在不需要时支付 Arc 价格(我对对象的生命周期有清晰的认识,真的不需要计算引用) .

我看到的当前解决方案是拥有一个静态对象并使用它而不是特定于 MyServer 的对象,但我希望尽可能避免这种丑陋程度。

我来自 golang,这不是问题(我可以使用对象绑定方法作为处理程序)。所以我的问题是:如何从 Rust 中的 HTTP 处理程序轻松访问共享的不可变引用?

请注意,我之前没有使用镍或铁的经验(到目前为止我个人使用的是 SCGI)。

我在编译您的 Nickel 示例时遇到的错误是:

<nickel macros>:7:9: 7:70 error: captured variable `obj` does not outlive the enclosing closure

错误发生在以下片段中:

server.utilize(router! {
    get "/foo" => |_req, _res| {
        obj.foo();
    }
});

现在,router! 只是一个花哨的宏,用于将您的闭包包装在 Middleware 中,并内置了一些额外的检查。对于我们的调查,我们可能想深入了解并使用Middleware直接。

不幸的是,Nickel 明确要求 Middleware 具有 'static 的使用寿命。这是 Nickel API 设计的一个怪癖,与 Rust 本身没有太多关系(除了 Rust 允许库向用户要求这些东西的事实)。

然后我看到两个选项。首先是使用我们对对象生命周期的高级知识(Nickel 不知道我们的对象比服务器还长,但我们知道)并告诉编译器。编译器允许我们使用有用的 unsafetransmute 原语来展示我们的高级知识。

在这里,正在工作:unsafe.rs

在 Rust 中 unsafe 表示 "this piece of code is safe because the programmer said so"。每个 unsafe 块都必须满足程序员和编译器之间的这个安全契约。在这种情况下,我们知道该对象的寿命比服务器长,因此可以维持安全保证。

第二种选择是为满足 Nickel API 要求的技巧付出代价。在这里,我们为此使用了作用域线程本地存储:thread_local.rs.

底线:镍 API 的要求使您可以跳过一些障碍,到达您想要的位置。我还没有调查过 Iron API。我有一种感觉,使用较低级别的 Hyper API.

,你可能会有更好的运气