这里有一个测试:
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
是纯的。但你的网络部分不是:这取决于当前时间。
这样,每次time
Web部件是";运行";(这意味着它将获得一个上下文作为参数(,它将运行DateTime.UtcNow
,然后将其传递给Successful.OK
,然后将上下文传递给生成的函数。