不理解Suave API,总是返回相同的结果



这里有一个测试:

open System
open System.Threading
open Newtonsoft.Json
open Suave
open Suave.Logging
open Suave.Operators
open Suave.Filters
open Suave.Writers

let private configuration = {
defaultConfig with
bindings   = [ HttpBinding.createSimple HTTP "0.0.0.0" 80 ]
}

let private getServerTime () : WebPart =
DateTime.UtcNow |> JsonConvert.SerializeObject |> Successful.OK >=> setMimeType "application/json"

let private webApplication =
choose
[
GET >=> choose
[
path "/servertime"   >=> getServerTime ()
]
]
let start () =
let listening, server = startWebServerAsync configuration webApplication
server    |> Async.Start
listening |> Async.RunSynchronously |> ignore

[<EntryPoint>]
let main _ =
start()
Thread.Sleep(Timeout.Infinite)
0

在本例中,getServerTime函数被调用一次,就这样,对端点的每次后续调用都将返回原始结果。

我不明白为什么?当我将pathScan与参数一起使用时,函数每次都会被调用,正如预期的那样,但在这种情况下,通过简单的get,只有第一次调用被完成,而这被定义为一个函数。

但我也根本不理解文档(从文档的流程、内容和整个文档结构来看…(,所以答案可能很简单:(

首先,我强烈建议你学习一元作曲。这是理解这些事情的必要基础。它将让您了解什么是>=>>>=以及如何处理它们。

至于手头的问题:是的,您将getServerTime定义为一个函数,但这并不重要,因为在构造webApplication值的过程中,该函数只被调用一次。

服务器的结构使得它实际上是一个函数HttpContext -> Async<HttpContext option>。它获取一个请求上下文并返回它的修改版本。所有这些组合子——choose>=>等等——都与这些函数一起工作。

表达式path "/servertime"也是这样的函数。字面上你可以这样称呼它:

let httpCtx = ...
let newCtxAsync = path "/servertime" httpCtx

此外,表达式getServerTime()也是这样的函数。所以你可以做:

let httpCtx = ...
let newCtxAsync = getServerTime () httpCtx

这就是WebPart类型。它是一个从上下文到新上下文的异步函数。

现在,>=>运算符所做的是组合这些函数。使它们通过管道将上下文从一个Web部件传递到下一个。仅此而已。


当您编写getServerTime函数时,您创建了一个始终返回相同内容的WebPart。有点像这样:

let f x y = printf "x = %d" x
let g = f 42

这里,g是函数(就像WebPart是函数一样(,但无论何时调用它,它都会返回"x = 42"。为什么?因为我部分地应用了这个参数;"烘烤";在CCD_ 17的定义中。以相同的方式,当前时间是"0";"烘烤";在您在getServerTime中创建的WebPart中。

如果希望每次返回不同的时间,则需要每次重新创建WebPart。在每个调用上构造一个新的WebPart,其中一个调用的时间已经过了。这样做的最小更改可能是:

let private getServerTime () : WebPart =
let time : WebPart = fun ctx -> (DateTime.UtcNow |> string |> Successful.OK) ctx
time >=> setMimeType "text/plain"

从表面上看,time的定义可能很愚蠢:毕竟,let f x = g x总是可以被let f = g取代,对吧?嗯,不总是。只要g是纯的。但你的网络部分不是:这取决于当前时间。

这样,每次timeWeb部件是";运行";(这意味着它将获得一个上下文作为参数(,它将运行DateTime.UtcNow,然后将其传递给Successful.OK,然后将上下文传递给生成的函数。

最新更新