2017-12-27 430 views
1

我试图使用F#下面的代码片断发送异步POST请求火力地堡:特别是下列的操作,这允许匿名登录:F#异步HTTP请求 - 解析JSON响应

https://firebase.google.com/docs/reference/rest/auth/#section-sign-in-anonymously

let makePostRequest (url : string) (requestBody : string) = 
    let req = WebRequest.CreateHttp url 
    req.CookieContainer <- new CookieContainer() 
    req.Method <- "POST" 
    req.ProtocolVersion <- HttpVersion.Version10 
    let postBytes = requestBody |> System.Text.Encoding.ASCII.GetBytes 
    req.ContentLength <- postBytes.LongLength 
    req.ContentType <- "application/xml; charset=utf-8" 
    async{ 
     use! reqStream = req.GetRequestStreamAsync() |> Async.AwaitTask 
     do! reqStream.WriteAsync(postBytes, 0, postBytes.Length) |> Async.AwaitIAsyncResult |> Async.Ignore 
     reqStream.Close() 
     use! res = req.AsyncGetResponse() 
     use stream = res.GetResponseStream() 
     use reader = new StreamReader(stream) 
     let! rdata = reader.ReadToEndAsync() |> Async.AwaitTask   
     return rdata 
    } 

我打电话,如下所示:

let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXXXXXXX" 
    let data = "returnSecureToken=true" 
    makePostRequest url data 

我很新的F#,有点搞不清关于这是如何工作的。我如何从这个请求中获得JSON响应?我如何知道何时完成?这会阻止主线程上的UI吗?我做的是翻译的斯威夫特以下代码块:

Auth.auth().signInAnonymously(completion: { (user, error) in 

     if let err = error { 
      print(err.localizedDescription) 
      return 
     } 

    }) 

这里的一切对我来说很有意义,因为我们有一个完成块的方法执行完毕后调用的,而且我们知道,user变量包含从服务器获得的响应,这在F#中对我来说意义不大。

UPDATE:

继在意见的建议,我已引用F#数据:HTTP实用程序,并创建了下面的代码片段:

let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXX" 
Http.RequestString 
    (url, 
     headers = [ ContentType HttpContentTypes.Json ], 
     body = TextRequest """ {"returnSecureToken": true} """) 

然而,这会产生错误The value, namespace, type or module Http is not defined

UPDATE 2: 我已经解决了以下代码:

let fetchUrl callback url (requestBody : string) =   
    let req = WebRequest.Create(Uri(url)) 
    req.Method <- "POST" 
    let postBytes = requestBody |> System.Text.Encoding.ASCII.GetBytes 
    req.ContentLength <- postBytes.LongLength 
    req.ContentType <- "application/json; charset=utf-8" 
    let reqStream = req.GetRequestStream() 
    reqStream.Write(postBytes, 0, postBytes.Length); 
    reqStream.Close() 

    use resp = req.GetResponse() 
    use stream = resp.GetResponseStream() 
    use reader = new IO.StreamReader(stream) 
    callback reader url 

let myCallback (reader:IO.StreamReader) url = 
    let html = reader.ReadToEnd() 
    let html1000 = html.Substring(0,1000) 
    printfn "Downloaded %s. First 1000 is %s" url html1000 
    html  // return all the html 


let openLandlord() = 
    let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXXXXXXXXX" 
    let requestBody = """ {"returnSecureToken": true} """ 
    fetchUrl myCallback url requestBody 

以下这里的例子:

https://fsharpforfunandprofit.com/posts/fvsc-download/

但是当我打电话openLandlord功能在这里:

override x.ViewDidLoad() = 
    base.ViewDidLoad() 
    openLandlord() 

我收到以下错误:

这种表达预计有型但是这里有字符串。

enter image description here

错误:

  1. 在或结合在此点之前的不完全的结构化构建体。
  2. 未定义构造函数请求的值。
  3. 成员定义中的意外关键字匹配。
  4. 未定义值,名称空间,类型或模块响应。
  5. 成员定义中意外标识。
+1

你的问题太广泛了。并且您将一个高级API与另一个低级API进行比较。如果需要,可以将请求处理委托给库。例如,FSharp.Data具有很好的HTTP实用程序:http://fsharp.github.io/FSharp.Data/library/Http.html –

+0

我不认为它太宽泛...我想要做的就是发送一个HTTP POST请求异步而不会阻塞UI,然后在闭包块(或与其等效的东西)中获得此请求的JSON响应。我试过使用Http.fs,但是这不会为xamarinios安装显然 – Alk

+1

对不起,我刚刚阅读“有点困惑,这是如何工作的”作为鼓励我详细解释代码的细节,这需要太广泛的答案。如果您只想从响应数据获取JSON,则可以使用FSharp.Data或.NET Newtonsoft.JSON中的特定于F#的JSON类型提供程序。两者都有很多例子。如果您使用异步操作,UI线程将会很好。 –

回答

1

检查下面的代码:

open System 
open System.Net 
open FSharp.Data 

type Response = JsonProvider<""" { "name":"John", "age":94 } """> 

[<EntryPoint>] 
let main argv = 
    let request() = 
    async { 
     let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXX" 
     return! Http.AsyncRequestString 
     (url, 
      headers = [ "Content-Type", HttpContentTypes.Json ], 
      body = TextRequest """ {"returnSecureToken": true} """) 
    } |> Async.Catch 
    let result = request() 
       |> Async.RunSynchronously 
    match result with 
    | Choice1Of2 text -> let json = Response.Parse text 
         printfn "name: %A" json.Name 
    | Choice2Of2 e -> printfn "request failed: %A" e 
    0 // return an integer exit code 

如果类型提供不与您的设置工作,这可能会帮助:https://github.com/Microsoft/visualfsharp/issues/3303

更换样品JSON什么是从服务的预期。

+0

可否请你看看更新? – Alk

+0

这不是异步,它不解析JSON,它不会捕获错误... –

+0

我知道,问题是我无法让您的代码在iOS设置中工作我必须将其构建,我对F#非常陌生,并且不太了解代码中的控制流程以及如何使用它,我不想简单地复制粘贴某些我无法理解的内容......而代码更直截了当,我明白它是如何工作的。 – Alk