我正在尝试做一些应该简单的事情:向网址发出GET请求。但是,当我搜索如何做到这一点的例子时,我经常会遇到像this这样近乎乱哄哄的事。
有谁知道如何使用OCaml发出简单的HTTP请求?我是一个带有一些Haskell exp的OCaml新手。
注意:
使用尽可能低的OCaml的解决方案将是理想的。我已经看过使用了Cohttp
库,但我对本机(?)HTTP
OCaml库或其他类似的东西更感兴趣。
为了回应@antron
,我们非常感谢使用最低级别本地OCaml的解决方案。我被引导相信这将涉及Unix
库。但是,如果有另一个不涉及第三方库的解决方案,那将同样受欢迎。
使用Cohttp库。见Client example。
相关的是:
Cohttp_lwt_unix.Client.get (Uri.of_string "http://www.reddit.com/")
这给你在(response, body)
monad里面有一对Lwt
。 response
基本上是一个记录,body
是一个流。本例的其余部分只是打印一些有趣的内容。
在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(我已经包含了在线版的链接);这是一本好书。
对于OCaml中的低级Unix编程(即使你不太了解它),我推荐优秀的书籍Unix System Programming in OCaml。它会告诉你如何编写你想要的客户端。
对于那些寻找一个非常独立的解决方案的人来说,我找到了一个至少应该适用于任何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 ()
这不是一个班轮,但它是相对直接的。