【问题标题】:How to use OCaml Url and Cohttp如何使用 OCaml Url 和 Cohttp
【发布时间】:2013-12-02 11:30:06
【问题描述】:

我正在尝试使用 OCaml 的 Url 和 Cohttp 模块来访问 API 和检索 JSON 数据。我不是想以异步方式做到这一点。我没有网络/网络编程的经验,所有的模块文档都只是给出了类型和方法的签名(对我没有太大帮助,因为我不知道它们是做什么的)。我正在尝试访问 bitstamp API 并检索比特币的投标价格。到目前为止我只知道如何声明一个URI

    let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/";;

但我现在知道如何调用 uri 以检索 json 数据。我如何使用现有的库来实现这一点?我已经知道如何将 json 数据解析为我需要的类型。

【问题讨论】:

    标签: json api http url ocaml


    【解决方案1】:

    Cohttp 要求您使用 Lwt 或 Async,因此您必须学习其中一个库。幸运的是,检索 JSON 文本并对其进行解析正是新的 Real World OCaml 书中的示例之一,您可以在线免费阅读 here。第 18 章介绍 Async 和 Cohttp,第 15 章介绍 JSON 解析。

    现在,实际回答您的问题:

    $ utop
    utop # #require "lwt.syntax";;
    utop # #require "core";;
    utop # open Core.Std;;
    utop # #require "cohttp.lwt";;
    utop # #require "uri";;
    
    utop # let get_uri uri : string Or_error.t Lwt.t =
      let open Lwt in
      match_lwt Cohttp_lwt_unix.Client.get uri with
      | None ->
        let msg = sprintf "%s: no reply" (Uri.to_string uri) in
        return (Or_error.error_string msg)
      | Some (_, body) -> (
          lwt body = Cohttp_lwt_body.string_of_body body in
          return (Ok body)
        );;
    
    utop # let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/";;
    
    utop # get_uri bitstamp_uri;;
    - : string Or_error.t =
    Core_kernel.Result.Ok
    "{\"high\": \"755.00\", \"last\": \"675.20\", \"timestamp\": \"1384841189\", \"bid\": \"675.10\", \"volume\": \"72858.24608402\", \"low\": \"471.26\", \"ask\": \"675.20\"}" 
    

    在这种情况下,我使用了 Core 和 Lwt。 RWO 书使用异步。如果你想完全避免异步编程的复杂性,那么你就不能使用 Cohttp。

    【讨论】:

    • 感谢这有很大帮助,但是我找不到模块 Cohttp_lwt_unix(我确实安装了 cohttp)。此外,对于 cohttp 中的所有方法,我都找不到任何好的文档/示例。我已经通过 ocamldoc 创建了 html,它似乎不完整。你知道我在哪里可以获得更多关于这方面的信息吗?
    • Cohttp 被分成 3 个 ocamlfind 包:ocamlfind list | grep cohttp。请务必加载 cohttp.lwt 以使用 lwt 模块。这是因为大多数应用程序将使用 Async 或 Lwt,而不是同时使用两者。这样,如果您使用 Lwt,您就不必加载所有 Async,反之亦然。
    • 关于文档,我只知道我提到的 Real World OCaml 中的章节。 OCamldoc 经常在复杂代码上失败;直接读取 mli 文件更容易。不幸的是,没有什么其他的了。
    • 当我运行$ ocamlfind list | grep cohttp 时,返回的唯一结果是cohttpcohttp.async。我试图找到cohttp.lwt,但我在任何地方都找不到源,而且它似乎在 opam 上不可用。你知道我可以从哪里得到它吗?编辑:我在 github 上找到了源文件,但是我不确定如何/在哪里保存它们,因为我的 .opam/system/lib 目录中已经有 Async、Cohttp 和 Lwt 目录。
    • 只要opam install lwt。这也将自动升级您的 cohttp 安装以包含 cohttp.lwt。由于 cohttp 可以与 async 或 lwt 一起使用,因此它的 opam 包旨在让您在安装了这些先决条件中的一个或两个时安装它。
    【解决方案2】:

    这是使用Curl 的答案,不需要您了解异步。 (作为记录,我认为你最好使用 Async 和 Cohttp!)

    (* Wrapper for Curl. Used by the function below. *)
    let fetch (url: string) (f: string -> int): unit =
      let c = Curl.init () in
      Curl.set_url c url;
      Curl.set_followlocation c true;
      Curl.set_writefunction c f;
      Curl.perform c;
      Curl.cleanup c
    ;;
    
    (* [get url] fetches the document at [url] and returns its contents as a string. *)
    let get (url: string): string =
      let buf = Buffer.create 16 in
      fetch url (fun s -> Buffer.add_string buf s; String.length s);
      Buffer.contents buf
    ;;
    

    【讨论】:

    • 我想我希望这个例子更加独立?但是,是的,当然,Buffer 更有意义。
    【解决方案3】:

    这是另一个您可能会发现有用的示例。在此示例中,我不依赖 Core 或 Async,您应该能够将其作为脚本运行,而不是在顶层运行。

    #! /usr/bin/env ocaml
    
    #use "topfind"
    #require "uri"
    #require "cohttp.lwt"
    
    let fetch uri =
      let open Lwt in
      Cohttp_lwt_unix.Client.get uri >>= fun (resp, body) ->
      Cohttp_lwt_body.to_string body >>= fun b ->
      Lwt_io.printl b
    
    let () =
      let bitstamp_uri = Uri.of_string "http://www.bitstamp.net/api/ticker/" in
      Lwt_main.run (fetch bitstamp_uri)
    

    【讨论】:

      【解决方案4】:
      utop [0]: #require "async";;
      utop [1]: #require "cohttp.async";;
      utop [2]: open Async.Std;;
      utop [3]:  let get_uri uri_str = Cohttp_async.Client.get @@ Uri.of_string uri_str
      >>= fun (_, body) -> Cohttp_async.Body.to_string body;;
      val get_uri : string -> string Deferred.t = <fun>
      utop [4]: get_uri "http://www.bitstamp.net/api/ticker/";;
      - : string = "{\"high\": \"661.11\", \"last\": \"652.65\", \"timestamp\": 
      \"1402207587\", \"bid\": \"651.99\", \"vwap\": \"654.52\", \"volume\": 
      \"3022.07902416\", \"low\": \"648.87\", \"ask\": \"654.29\"}"
      

      我花了一些时间才弄明白,所以我把代码贴在这里。

      【讨论】:

        猜你喜欢
        • 2023-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-25
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 2014-06-07
        相关资源
        最近更新 更多