如何在F#中使用HttpClient?

12

我是F#的新手,对于从C#开发人员的角度理解F#中的异步操作感到困惑。比如以下C#代码片段:

var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();

如何用F#写同样的代码?

5个回答

20

这里有一个函数,应该可以实现你所需的功能(请注意,你需要将代码放在异步计算表达式中,以便使用let!语法):

let getAsync (url:string) = 
    async {
        let httpClient = new System.Net.Http.HttpClient()
        let! response = httpClient.GetAsync(url) |> Async.AwaitTask
        response.EnsureSuccessStatusCode () |> ignore
        let! content = response.Content.ReadAsStringAsync() |> Async.AwaitTask
        return content
    }

6
第一个和第二个 let 应该改为 use,因为 httpClientresponse 都是可释放资源(IDisposable)。 - Cogwheel
很可能不行,因为 HttpClient 在这方面是有特殊性的。 - psfinaki

8
如果你正在使用F#中的HttpClient,那么至少要阅读并了解Http.fs中已经建立的模式。TL;DR ... 但是要小心分享。正如@pimbrouwers所指出的那样,需要注意的是你不一定必须使用它,可以在您的上下文中对其进行子集和/或演化,以获得更好的适配抽象(并在途中获得学习的好处)。至此为止:在F#中,通常惯用的做法是将很少使用和/或过度特定的帮助程序保存在非中心位置。

1
请勿误解。但我认为直接引用库作为答案是一种逃避责任的行为。当然,最终你可能会使用它。但从我的角度来看,你应该首先自己去探索。否则,我们最终会得到一群程序员,他们已经远离了他们实际要做的事情,只能使用外部库来完成工作。ADO.NET就是一个完美的例子。你会惊讶地发现有多少 .NET 开发人员不知道如何处理 SqlConnection 和执行 SqlCommand - pim
1
重点是,首先自己尝试一下。犯错误。彻底搞砸它(我知道我总是这样做)。但在这个过程中实际上学到了东西。 - pim
1
我有点同意;今天我不会写出相同的答案。然而,我的观点仍然存在,即在没有了解广泛使用的库的情况下,不要为 HttpClient 编写 F# 封装 - 例如对于相同概念保持相同的命名等。我会进行编辑以反映这一点。 - Ruben Bartelink

6
您可以使用async
let readString (url: Uri) = async {
    let httpClient = new HttpClient();
    let! response = httpClient.GetAsync(url) |> Async.AwaitTask
    response.EnsureSuccessStatusCode() |> ignore
    return! response.Content.ReadAsStringAsync() |> Async.AwaitTask
}

2

我个人的看法是,当使用EnsureSuccessStatusCode()时,我们应该处理HttpRequestException异常。

下面是一个模块的开头,它包装了HttpClient,将URL的响应缓冲为一个string,并安全地封装在Result<'a,'b>中,以提高容错性。

注:Original Answer翻译成"最初的回答"

module Http =
    open System    
    open System.Net.Http

    let getStringAsync url =
        async {
            let httpClient = new HttpClient() 
            // This can be easily be made into a HttpClientFactory.Create() call
            // if you're using >= netcore2.1

            try 
                use! resp = httpClient.GetAsync(Uri(url), HttpCompletionOption.ResponseHeadersRead) |> Async.AwaitTask                       
                resp.EnsureSuccessStatusCode |> ignore

                let! str = resp.Content.ReadAsStringAsync() |> Async.AwaitTask
                return Ok str
            with
            | :? HttpRequestException as ex -> return ex.Message |> Error
        }

1

只需使用FSharp.Control.FusionTasks,您就可以拥有清晰的语法,无需像|> Async.AwaitTask那样。

   let httpClient = new System.Net.Http.HttpClient ()

   let getAsync (url:string) = 
    async {
        let! response = httpClient.GetAsync url
        response.EnsureSuccessStatusCode () |> ignore
        let! content = response.Content.ReadAsStringAsync ()
        return content
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接