2017-12-27 428 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