【问题标题】:How do I make a simple GET request in OCaml?如何在 OCaml 中发出简单的 GET 请求?
【发布时间】:2016-07-04 09:15:28
【问题描述】:

我正在尝试做一些简单的事情:向 url 发出 GET 请求。但是,当我搜索如何执行此操作的示例时,我经常会遇到像 this 这样的近乎胡言乱语。

有人知道如何使用 OCaml 发出简单的 HTTP 请求吗?我是一名 OCaml 新手,有一些 Haskell 经验。

注意:

使用尽可能低的 OCaml 级别的解决方案将是理想的。我已经看到使用了 Cohttp 库,但我对原生 (?) HTTP OCaml 库或类似的东西更感兴趣。

作为对@antron 的回应,非常感谢使用尽可能低级别的本机 OCaml 的解决方案。我被引导相信这将涉及Unix 库。但是,如果有另一个不涉及第三方库的解决方案,那将同样受欢迎。

【问题讨论】:

  • 根据我对推荐 Cohttp 的回答的评论,OCaml 中没有这样的库。 OCaml 标准库非常简朴,很多任务都使用社区库。如果你想查看 OCaml 打包的库列表,在这里:caml.inria.fr/pub/docs/manual-ocaml/libref/index.html
  • 如果你想要 OCaml 中的“最低级别”,答案将是套接字,(例如标准模块Unix)然后它就不再是简单了.如果您想要这么低的级别,请澄清您的问题。
  • 让我大吃一惊的是,任何人都会对这样的问题投反对票,堆栈溢出开发人员调查显示,它为大多数开发人员提供了基本的编码。 @dopatraman 我还建议您查看hyegar.com/2015/10/20/so-youre-learning-ocaml 以快速提高工作效率。
  • @antron 更新了问题。
  • @dopatraman 您对套接字编程有多少背景?你想在Unix中使用socketconnectsendrecvclose,甚至可能是select,但我不知道这对你是否立即有意义,或者你想要一个详细的答案。如果您选择不使用任何 HTTP 库或并发 monad(在标准库中也找不到),那么它基本上是 OCaml 中的 C 系统编程。

标签: http ocaml


【解决方案1】:

使用 Cohttp 库。请参阅Client example

相关行是:

Cohttp_lwt_unix.Client.get (Uri.of_string "http://www.reddit.com/")

这会在Lwt monad 中为您提供一对(response, body)response 基本上是一条记录,body 是一条流。该示例的其余部分只是打印其中一些有趣的部分。

【讨论】:

  • 您知道如何使用较低级别的代码吗?是否有用于 OCaml 的基本 Http 库?我正在尝试从头开始学习这种语言。
  • Cohttp 是 OCaml 中基本 HTTP 库的候选者之一(另一个是 Ocamlnet,如您发布的链接中所示)。如果你想更底层,你必须直接从模块Unix(或Lwt_unix,如果你想使用并发单子——并发单子的另一个选择是异步库)中使用套接字。没有 OCaml 本身支持的标准 HTTP 库,但我认为社区目前或多或少地选择了 Cohttp。
【解决方案2】:

也许在 OCaml 中发送 GET 请求的最基本方法是使用 Unix 库和来自 Pervasives 的基本输入/输出例程。

这是一个非常简单的例子:

let ip = Unix.((gethostbyname "caml.inria.fr").h_addr_list.(0))
let addr = Unix.ADDR_INET (ip, 80)

let sock = Unix.(socket PF_INET SOCK_STREAM 0)
let _ = Unix.connect sock addr

let in_ch = Unix.in_channel_of_descr sock
let out_ch = Unix.out_channel_of_descr sock

let _ =
  output_string out_ch
    "GET /pub/docs/manual-ocaml/index.html HTTP/1.1\r\n\
     Host: caml.inria.fr\r\n\
     User-Agent: OCaml\r\n\
     Connection: close\r\n\
     \r\n";
  flush out_ch

let _ =
  try
    while true do
      print_string (input_line in_ch)
    done
  with End_of_file ->
    Unix.close sock

如果将open Unix 放在文件顶部,则不需要Unix. 前缀,但为了清楚起见,我更愿意保留它们。

程序可以用ocamlc unix.cma -o get get.ml编译成字节码。

我同意 @ChriS 的建议,阅读 Leroy 和 Rémy 的 Unix system programming in OCaml(我已包含在线版本的链接);这是一本好书。

【讨论】:

    【解决方案3】:

    对于 OCaml 中的低级 Unix 编程(即使你不太了解它),我推荐这本优秀的书 Unix System Programming in OCaml。它会告诉你如何编写你想要的客户端。

    【讨论】:

      【解决方案4】:

      对于那些寻找完全独立的解决方案的人,我找到了一个至少应该可以在任何 Unix* 等操作系统上运行的解决方案。

      来自Rosetta Code

      let try_finalise f x finally y =
        let res = try f x with e -> finally y; raise e in
        finally y;
        res
      
      let rec restart_on_EINTR f x =
        try f x with Unix.Unix_error (Unix.EINTR, _, _) -> restart_on_EINTR f x
      
      let double_fork_treatment server service (client_descr, _ as client) =
        let treat () =
          match Unix.fork () with
          | 0 ->
              if Unix.fork () <> 0 then exit 0;
              Unix.close server; service client; exit 0
          | k ->
              ignore (restart_on_EINTR (Unix.waitpid []) k)
        in
        try_finalise treat () Unix.close client_descr
      
      let install_tcp_server_socket addr =
        let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
        try
          Unix.bind s addr;
          Unix.listen s 10;
          s
        with e -> Unix.close s; raise e
      
      let tcp_server treat_connection addr =
        ignore (Sys.signal Sys.sigpipe Sys.Signal_ignore);
        let server_sock = install_tcp_server_socket addr in
        while true do
          let client = restart_on_EINTR Unix.accept server_sock in 
          treat_connection server_sock client 
        done
      
      let server () =
        let port = 8080 in
        let host = (Unix.gethostbyname (Unix.gethostname())).Unix.h_addr_list.(0) in 
        let addr = Unix.ADDR_INET (host, port) in
        let treat sock (client_sock, client_addr as client) =
          let service (s, _) =
            let response = "\
              HTTP/1.1 200 OK\r\n\
              Content-Type: text/html; charset=UTF-8\r\n\r\n\
              <html><head><title>Goodbye, world!</title>\
              <style>body { background-color: #0FF }\
              h1 { font-size:3em; color: black; }</style></head>\
              <body><h1>Goodbye, world!</h1></body></html>\r\n"
            in
            Unix.write s response 0 (String.length response);
          in
          double_fork_treatment sock service client
        in
        tcp_server treat addr
      
      let _ =
        Unix.handle_unix_error server ()
      

      这不是一个单一的班轮,而是相对简单的。

      【讨论】:

      • 这看起来更像是一个服务器而不是一个客户端。
      猜你喜欢
      • 2018-08-25
      • 2011-03-13
      • 2018-04-02
      • 2019-11-09
      • 1970-01-01
      • 1970-01-01
      • 2021-03-12
      • 2020-02-15
      • 1970-01-01
      相关资源
      最近更新 更多