Erlang HTTP

该文档用于提供erlang Http常用的一些含义和处理http请求。

HTTP Client

配置

启动Inets应用程序启动HTTP客户端默认配置文件,然后该Erlang节点上的所有进程都可以使用该配置文件。其他配置文件也可以在应用程序启动时启动,或者配置可以在运行时动态启动和停止。每个客户端配置文件生成一个新进程来处理每个请求,除非持久连接可以使用或不使用管道。客户端添加一个Host报头和一个空的te报头,如果在请求中没有这样的报头。
客户端支持IPv6,只要底层机制也这样做。
下面的内容将放在Erlang节点应用程序配置文件中,以便在应用程序启动时启动配置文件:

1
[{inets, [{services, [{httpc, PropertyList}]}]}]

如何使用

启动Inet

1
inets:start().

以下调用使用默认的客户端配置文件。使用代理,但对本地主机的请求除外。这适用于以下所有请求。

1
2
3
2 > httpc:set_options([{proxy, {{"www-proxy.mycompany.com", 8000},
["localhost"]}}]).
ok

下面是一个很普通的同步请求

1
2
3 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
a

使用所有的默认值,get请求可以这样写:

1
2
4 > {ok, {{Version, 200, ReasonPhrase}, Headers, Body}} =
httpc:request("http://www.erlang.org").

下面是一个普通的异步请求

1
2
5 > {ok, RequestId} =
httpc:request(get, {"http://www.erlang.org", []}, [], [{sync, false}]).

结果以{http, {RequestId, result}}的形式发送到调用进程。
在这种情况下,调用进程是shell,因此接收到以下结果:

1
2
6 > receive {http, {RequestId, Result}} -> ok after 500 -> error end.
ok

这发送一个请求与指定的连接头:

1
2
7 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} =
httpc:request(get, {"http://www.erlang.org", [{"connection", "close"}]},[], []).

通过unix域套接字发送一个HTTP请求

1
2
8 > httpc:set_options([{ipfamily, local},{unix_socket,"/tmp/unix_socket/consul_http.sock"}]).
9 > {ok, {{NewVersion, 200, NewReasonPhrase}, NewHeaders, NewBody}} = httpc:request(put, {"http:///v1/kv/foo", [], [], "hello"}, [], []).

启动HTTP客户端

1
2
10 > {ok, Pid} = inets:start(httpc, [{profile, foo}]).
{ok, <0.45.0>}

新的配置文件没有代理设置,所以连接被拒绝:

1
2
11 > httpc:request("http://www.erlang.org", foo).
{error, econnrefused}

关闭客户端配置

1
2
12 > inets:stop(httpc, foo).
ok

除此之外,还可以使用Pid代替关闭。

httpc

httpc模块是在OTP R13B04中引入的。该模块根据RFC 2616向HTTP-1.1兼容的客户端提供API。不支持缓存。
当启动Inets应用程序时,将启动默认配置文件的管理器进程。此API中不显式使用概要文件的函数将访问默认概要文件。配置文件跟踪代理选项、cookie和其他可应用于多个请求的选项。
如果使用模式https,则必须启动SSL应用程序。当https链接需要通过代理时,使用HTTP-1.1的CONNECT方法扩展来建立隧道,然后将连接升级到TLS。但是,不支持根据RFC 2817进行的“TLS升级”。
管道仅在设置管道超时时使用,否则将使用不适用管道的持久连接。也就是说,客户机总是在发送下一个请求之前等待前一个响应。

HTTP 数据类型

method() = head | get | put | post | trace | options | delete | patch
request() = {url(), headers()} | {url(), headers(), content_type(), body()}
url() = string()
status_line() = {http_version(), status_code(), reason_phrase()}
http_version() = string() 例如”http/1.1”
status_code() = integer()
reason_phrase() = string()
content_type() = string()
headers() = [header()]
header() = {field(), value()}
field() = string()
value() = string()
body() = string() | binary() | {fun(accumulator) -> body_processing_result(), accumulator()}
accumulator() = term(),
filename() = string().

Http客户服务启动/停止

HTTP客户机可以配置为在Inets应用程序启动时启动,或者在运行时通过调用Inets应用程序API inets:start(httpc, ServiceConfig)或Inets:start(httpc, ServiceConfig, How)来动态启动。
配置如下:
{profile, profile()}
配置文件的名称。这个选项是强制性的。
{data_dir, path()}
配置文件可以保存持久数据的目录。如果省略,所有cookie将会被视为会话cookie。
可以使用inets:stop(httpc, Pid)或inets:stop(httpc, Profile)来停止客户机。

常用函数

1.cancel_request(RequestId) ->
cancel_request(RequestId, Profile) -> ok.
RequestId= request_id() request/4函数返回的唯一标识符。
Profile = profile() | pid()
当以stand_alone模式启动时,只能使用pid。
取消异步HTTP请求。注意,这并不保证请求响应不会被传递。因为它是异步的,所以当取消到达时请求可能已经完成。

2.cookie_header(Url) ->
cookie_header(Url, Profile | Opts) -> header() | {error, Reason}
cookie_header(Url, Opts, Profile) -> header() | {error, Reason}
Url = url()
Opts = [cookie_header_opt()]
Profile = profile() | pid() 当以stand_alone模式启动时
cookie_header_opt() = {ipv6_host_with_brackets, boolean()}
返回在使用profile配置文件向Url发出请求时的cookie头。如果没有指定配置文件,则使用默认配置文件。
选项ipv6_host_with_bracket处理如何解析IPv6地址。

3.get_options(OptionItems) -> {ok, value} | {error, Reason}
get_options(OptionItems, Profile) -> {ok, value} | {error, Reason}
OptionItems = all | [option_item()]
option_item() = proxy | https_proxy | max_sessions | keep_alive_timeout | max_keep_alive_length | pipeline_timeout | max_pipeline_length | cookies | ipfamily | ip | port | socket_opts | verbose | unix_socket
Values = [{option_item(), term()}]
Reason = term()
检索客户端当前使用的选项。

4.info() -> list()
info(Profile) -> list()
Profile = profile() | pid()
生成杂项信息的列表。用于调试。如果没有指定配置文件,则使用默认配置文件。

5.reset_cookies() -> void()
reset_cookies(Profile) -> void().
重置(清除)指定配置文件的cookie数据库。如果没有指定配置文件,则使用默认配置文件。

6.request(Url) ->
request(Url, Profile) -> {ok, Result} | {error, Reason}
Url = url()
Result = {status_line(), headers(), Body} | {status_code(), Body} | request_id()
Body = string() | binary()
Profile = profile() | pid()
Reason = term()
调用这个函数等价于httpc:request(get, {Url,[]}, [], []).

7.request(Method, Request, HTTPOptions, Options) ->
request(Method, Request, HTTPOptions, Options, Profile) -> {ok, Result} | {ok, saved_to_file} | {error, Reason}
Method = method()
Request = request()
HTTPOptions = http_options()
http_options() = [http_option()]
http_option() = {timeout, timeout()} | {connect_timeout, timeout()} | {ssl, ssloptions()} | {essl, ssloptions()} | {autoredirect, boolean()} | {proxy_auth, {userstring(), passwordstring()}} | {version, http_version()} | {relaxed, boolean()}
timeout() = integer() >= 0 | infinity
Options = [option()]
option() = {sync, boolean()} | {stream, stream_to()} | {body_format, body_format()} | {full_result, boolean()} | {headers_as_is, boolean()} | {socket_opts, socket_opts()} | {receiver, receiver()} | {ipv6_host_with_brackets, boolean()}
stream_to() = none | self | {self, once} | filename()
socket_opts() = [socket_opt()]
receiver() = pid() | function()/1 | {Module, Function, Args}
Module = atom()
Function = atom()
Args = list()
body_format() = string | binary
Result = {status_line(), headers(), Body} | {status_code(), Body} | request_id()
Body = string() | binary()
Profile = profile() | pid()
Reason = term()
发送一个Http请求。该函数可以是同步的,也可以是异步的。在后一种情况下,函数返回{ok, RequestId},然后根据该值将信息传递给接受者。
http_option()的详细说明:

  • timeout
    请求的超时时间。
    发送请求时,始终开始计算。
    时间以毫秒为单位。
    默认为infinity
  • connect_timeout
    连接超时时间,在客户端连接到服务器的初始请求期间使用。
    时间以毫秒为单位。
    默认值是选项超时的值。
  • ssl
    这是SSL/TLS connectin 配置选项。
    默认为[]。有关可用选项,可以参考ssl:connect/[2,3,4]。
  • autoredirect
    客户端自动从新的URI中检索信息,并将其作为结果返回,而不是作为30X-result代码。
    对于一些30X-result代码,自动重定向是不允许的。在这些情况下,总是返回30X-result。
    默认是true。
  • proxy_auth
    使用提供的用户名和密码的代理授权头被添加到请求中。
  • version
    可用于使客户端充当HTTP/1.0或HTTP/0.9客户端。默认情况下这是一个HTTP/1.1客户端。当使用HTTP/1.0时,不使用持久连接。
    默认是HTTP/1.1
  • relaxed
    如果设置为true,将启用针对已知服务器与http标准之间的偏差的工作区。
    默认是false。

选项option() 细节:

  • sync
    请求同步或异步的选项。
    默认是true。
  • stream
    将200或206响应的正文流到调用进程或文件中。当使用选项self流到调用进程时,以下流消息被发送到该进程:{http, {RequestId, stream_start, Headers}}, {http, {RequestId, stream, BinBodyPart}},和{http, {RequestId, stream_end, Headers}}。
    当使用选项 {self, once}流到调用进程时,第一个消息有一个额外的元素,即{http, {RequestId, stream_start, Headers, Pid}}。这是作为httpc:stream_next/1参数的进程id,用于触发下一条发送到调用进程的消息。
    注意,分块编码可以添加标题,因此stream_end消息中的标题比stream_start中的多。当流到一个文件并且请求是异步的,消息{http, {RequestId, saved_to_file}}被发送。
    默认是 none
  • body_format
    定义主体是要作为string还是binary文件交付。此选项仅对同步请求有效。
    默认是string。
  • full_result
    定义是否将“完整结果”返回给调用者
    默认是 true。
  • headers_as_js
    定义用户提供的标头是小写还是区分大小写。
    HTTP标准要求它们不区分大小写。只有在没有其他方法与服务器通信或处于测试目的时才使用此功能。使用此选项时,不会自动添加标题。所有必须的标头必须由用户提供。
    默认是false。
  • socket_opts
    此请求使用的套接字选项。
    覆盖函数set_options设置的任何值。
    HTTP客户机不会检查选项的有效性,它们被认为是正确的,并传递给ssl应用程序和inet驱动程序,如果选项不正确,ssl应用程序和inet驱动程序可能会拒绝它们。
    注意:设置socket_opts选项时不支持持久连接。当没有设置socket_opts时,当前实现假设请求到相同的主机,端口组合将使用相同的套接字选项。
    默认情况下,在建立连接时使用函数set_options/[1,2]设置的套接字选项。
  • receiver
    定义客户端如何交付异步请求的结果(sync的值为false)。
    pid()
    消息以{http, ReplyInfo}的格式发送到该进程。
    function/1
    信息通过调用提供的fun(ReplyInfo)传递给接收者。
    {Module, Function, Args}
    信息通过调用回调函数apply(Module, function, [ReplyInfo | Args])传递给接收者。
    在所有这些情况下,ReplyInfo的结构如下:
    {RequestId, saved_to_file}
    {RequestId, {error, Reason}}
    {RequestId, Result}
    {RequestId, stream_start, Headers}
    {RequestId, stream_start, Headers, HandlerPid}
    {RequestId, stream, BinBodyPart}
    {RequestId, stream_end, Headers}
    默认值是调用请求函数self()的进程pid。
  • ipv6_host_with_brackets
    定义在解析URI的主机端口部分时使用方括号(IPv6地址),如果这些方括号将被保留(true)或剥离(false)
    默认是false。

8.set_options(Options) ->
set_options(Options, Profile) -> ok | {error, Reason}
Types
Options = [Option]
Option = {proxy, {Proxy, NoProxy}}
| {https_proxy, {Proxy, NoProxy}}
| {max_sessions, MaxSessions}
| {max_keep_alive_length, MaxKeepAlive}
| {keep_alive_timeout, KeepAliveTimeout}
| {max_pipeline_length, MaxPipeline}
| {pipeline_timeout, PipelineTimeout}
| {cookie, CookieMode}
| {ipfamily, IpFamily}
| {ip, IpAddress}
| {port, Port}
| {socket_opts, socket_opts()}
| {verbose, VerboseMode}
| {unix_socket, UnixSocket}
Proxy = {Hostname, Port}

Hostname = string()
例如:”localhost”或”foo.bar.se”
Port = integer()
例如:8080
NoProxy = [NoProxyDesc]
NoProxyDesc = DomainDesc | HostName | IPDesc
DomainDesc = “.Domain”
例如:”
.ericsson.se”
IpDesc = string()
例如:”134.138”或”[FEDC:BA98”(所有IP地址以134.138或FEDC:BA98开头),”66.35.250.150”或”[2010:836B:4179:836B:4179]”(完整的IP地址)。代理默认为{undefined, []},即不配置代理,https_proxy默认为代理的值。
MaxSession = integer()
到主机的最大连接数。默认是2。
MaxKeepAlive = integer()
同一主机连接上未完成请求的最大数量。默认是5。
KeepAliveTimeout = integer()
如果一个持久连接的空闲时间超过了keep_alive_timeout(以毫秒为单位),则客户端关闭连接。服务器也可以有这样的超时,但不要认为这是理所当然的。默认值是120000(=2分钟)。
MaxPipeline = integer()
在连接到主机的管道上未完成的最大请求数。默认是2。
PipelineTimeout = integer()
如果一个持久连接的空闲时间超过pipeline_timeout(以毫秒为单位),则客户端关闭连接。默认值为0,这将导致不使用管道。
CookieMode = enable | disables | verify
如果启用了cookie,所有有效的cookie都会自动保存到客户端管理器的cookie数据库中。如果使用了选项verify,那么必须调用函数store_cookies/2才能保存cookie。默认是disables。
IpFamily = inet | inet6 | local
默认是inet
IpAddress = ip_address()
如果主机有多个网络接口,则此选项指定使用哪个网络接口。
Post = integer()
socket_opts = [socket_opt()]
这些选项被附加到客户端使用的套接字选项中。这些是启动新请求处理程序(用于初始连接)时的默认值。它们直接传递到底层传输(gen_tcp或SSL),无需验证。
VerboseMode = false | verbose | debug | trace
默认是false。此选项用于在客户机上打开(或关闭)不同级别的Erlang跟踪。它是一个调试特性。
UnixSocket = path()
通过unix域套接字发送HTTP请求的实验性选项。unix_socket的值应该是具有erlang进程读写权限的unix域套接字的完整路径。默认是undefined。