F#异步HTTP请求-解析JSON响应 [英] F# asynchronous HTTP request - parse JSON response
问题描述
我正在尝试使用以下 F#
片段向Firebase发送异步POST请求:特别是以下允许匿名登录的操作:
错误:
- 在绑定时或绑定时不完整的结构化构造.
- 未定义构造函数请求的值.
- 成员定义中的关键字意外匹配.
- 未定义值,名称空间,类型或模块Response.
- 在成员定义中标识意外.
检查以下代码:
开放系统打开System.Net打开FSharp.Data类型Response = JsonProvider<""{" name:" John," age:94}"">[< EntryPoint>]让main argv =让request()=异步{让url ="https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXX"返回!Http.AsyncRequestString(网址,标头= ["Content-Type",HttpContentTypes.Json],正文= TextRequest""{" returnSecureToken:true}"")} |>异步捕获让结果=请求()|>异步运行匹配结果与|Choice1Of2文字->让json = Response.Parse文本printfn名称:%A" json.Name|Choice2Of2 e->printfn请求失败:%A" e0//返回整数退出代码
如果类型提供的内容不适用于您的设置,则可能会有所帮助: https://github.com/Microsoft/visualfsharp/issues/3303
将示例JSON替换为服务期望的内容.
I'm trying to use the following snippet of F#
to send an asynchronous POST request to Firebase: in particular the following operation, which allows for anonymous sign in:
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
}
I am calling it as follows:
let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXXXXXXX"
let data = "returnSecureToken=true"
makePostRequest url data
I'm very new to F#
and a bit confused as to how this works. How can I obtain the JSON response from this request? How will I know when this is complete? Will this block the UI on the main thread? What I am doing is translating the following block of Swift code:
Auth.auth().signInAnonymously(completion: { (user, error) in
if let err = error {
print(err.localizedDescription)
return
}
})
Here everything makes sense to me as we have a completion block which gets called after the method is done executing, and we know that the user
variable will contain the response obtained from the server, it makes much less sense to me in F#.
UPDATE:
Following the suggestions in the comments, I have referenced F# Data: HTTP Utilities and created the following code snippet:
let url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=XXXXXXXXXXXX"
Http.RequestString
( url,
headers = [ ContentType HttpContentTypes.Json ],
body = TextRequest """ {"returnSecureToken": true} """)
However this produces the error The value, namespace, type or module Http is not defined
UPDATE 2: I have settled for the following code:
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
following the example here:
https://fsharpforfunandprofit.com/posts/fvsc-download/
however when I call the openLandlord
function here:
override x.ViewDidLoad () =
base.ViewDidLoad ()
openLandlord ()
I get the following error:
This expression was expected to have type uint but here has type string.
Errors:
- Incomplete structured construct at or before this point in binding.
- The value of constructor request is not defined.
- Unexpected keyword match in member definition.
- The value, namespace, type or module Response is not defined.
- Unexpected identified in member definition.
Check the following code:
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
If type provides are not working with your setup, this may help: https://github.com/Microsoft/visualfsharp/issues/3303
Replace sample JSON with what is expected from the service.
这篇关于F#异步HTTP请求-解析JSON响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!