如何在OCaml中发出简单的GET请求?

问题描述 投票:11回答:4

我正在尝试做一些应该简单的事情:向网址发出GET请求。但是,当我搜索如何做到这一点的例子时,我经常会遇到像this这样近乎乱哄哄的事。

有谁知道如何使用OCaml发出简单的HTTP请求?我是一个带有一些Haskell exp的OCaml新手。

注意:

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

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

http ocaml
4个回答
9
投票

使用Cohttp库。见Client example

相关的是:

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

这给你在(response, body) monad里面有一对Lwtresponse基本上是一个记录,body是一个流。本例的其余部分只是打印一些有趣的内容。


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

如果将Unix.放在文件的顶部,则不需要open Unix前缀,但为了清楚起见,我倾向于将它们留在中。

可以使用ocamlc unix.cma -o get get.ml将程序编译为字节代码。

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


1
投票

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


0
投票

对于那些寻找一个非常独立的解决方案的人来说,我找到了一个至少应该适用于任何Unix * OS的解决方案。

来自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 ()

这不是一个班轮,但它是相对直接的。

© www.soinside.com 2019 - 2024. All rights reserved.