查看源代码 httpc (inets v9.3.1)
一个 HTTP/1.1 客户端
此模块根据 RFC 2616 提供了一个与 HTTP/1.1 兼容的客户端的 API。不支持缓存。
注意
启动
Inets
应用程序时,将启动默认配置文件的管理器进程。此 API 中未显式使用配置文件的函数将访问默认配置文件。配置文件会跟踪代理选项、Cookie 和其他可应用于多个请求的选项。如果使用方案
https
,则必须启动SSL
应用程序。当https
链接需要通过代理时,将使用 HTTP-1.1 的 CONNECT 方法扩展来建立隧道,然后将连接升级为 TLS。但是,不支持根据 RFC 2817 的“TLS 升级”。仅当设置了管道超时时才使用管道,否则使用没有管道的持久连接。也就是说,客户端始终等待上一个响应,然后再发送下一个请求。
在 Inets 用户指南 中提供了一些示例。
HTTP 客户端服务启动和停止
可以配置 HTTP 客户端以在启动 Inets
应用程序时启动,或者通过调用 Inets
应用程序 API inets:start(httpc, ServiceConfig)
或 inets:start(httpc, ServiceConfig, How)
在运行时动态启动,请参阅 inets
。配置选项如下:
{profile, Profile :: atom() | pid()} - 配置文件的名称。此选项是必需的。
{data_dir, Path :: string()} - 配置文件可以保存持久数据的目录。如果省略,则所有 Cookie 都被视为会话 Cookie。
Path
表示文件路径或目录路径。
可以使用 inets:stop(httpc, Pid)
或 inets:stop(httpc, Profile)
停止客户端。
警告
请注意,
httpc
在内部处理之前会规范化输入 URI,并且当 URI 具有百分号 ("%") 字符时,应特别注意。百分号用作百分比编码八位字节的指示符,并且必须将百分比编码为 "%25" 以便该八位字节用作 URI 中的数据。例如,为了发送 URI 为
https://127.0.0.1/foo%25bar
的HTTP GET
请求,创建请求时必须对百分号进行百分比编码:httpc:request("https://127.0.0.1/foo%2525bar").
另请参阅
摘要
函数
取消异步 HTTP 请求。请注意,这不能保证不传递请求响应。因为它是异步的,所以当取消到达时,请求可能已经完成。
返回使用配置文件 Profile
向 Url
发出请求时将发送的 Cookie 标头。如果未指定配置文件,则使用默认配置文件。
返回使用配置文件 Profile
向 Url
发出请求时将发送的 Cookie 标头。如果未指定配置文件,则使用默认配置文件。
检索客户端当前使用的选项。
生成杂项信息列表。用于调试。如果未指定配置文件,则使用默认配置文件。
等效于 request/2
。
发送 HTTP 请求。该函数可以是同步的也可以是异步的。在后一种情况下,该函数返回 {ok, RequestId}
,然后根据该值将信息传递给 接收器
。
重置(清除)指定 Profile
的 Cookie 数据库。如果未指定配置文件,则使用默认配置文件。
设置用于后续请求的选项。
返回可用于验证主机的 SSL 选项,使用 public_key:cacerts_get()
读取 CA 证书,如果 WildcardHostName
为 true,则将 public_key:public_key:pkix_verify_hostname_match_fun(https)
中的主机名检查添加到选项中。
将 SetCookieHeaders
中定义的 Cookie 保存在客户端配置文件 Cookie 数据库中。如果选项 cookies
设置为 verify
,则调用此函数。如果未指定配置文件,则使用默认配置文件。
触发要流式的下一条消息,即与套接字的活动行为相同。
生成整个 Cookie 数据库的列表。用于调试/测试目的。如果未指定配置文件,则使用默认配置文件。
此函数仅用于调试。它生成会话数据库的稍微处理的转储。会话信息元组的第一个列表将包含内部格式的会话信息。如果代码按预期工作,则会话信息元组的最后两个列表应始终为空。如果未指定配置文件,则使用默认配置文件。
函数
-spec cancel_request(RequestId) -> ok when RequestId :: any().
等效于 cancel_request/2
。
取消异步 HTTP 请求。请注意,这不能保证不传递请求响应。因为它是异步的,所以当取消到达时,请求可能已经完成。
-spec cookie_header(Url) -> HttpHeader | {error, Reason} when Url :: uri_string:uri_string(), HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, Reason :: term().
等效于 cookie_header/2
。
-spec cookie_header(Url, ProfileOrOpts) -> HttpHeader | {error, Reason} when Url :: uri_string:uri_string(), HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, ProfileOrOpts :: Profile | Opts, Profile :: atom() | pid(), Opts :: [CookieHeaderOpt], CookieHeaderOpt :: {ipv6_host_with_brackets, boolean()}, Reason :: term().
返回使用配置文件 Profile
向 Url
发出请求时将发送的 Cookie 标头。如果未指定配置文件,则使用默认配置文件。
选项 ipv6_host_with_bracket
处理如何解析 IPv6 地址。有关详细信息,请参阅 request/4,5 的参数 Options
。
-spec cookie_header(Url, Opts, Profile) -> HttpHeader | {error, Reason} when Url :: uri_string:uri_string(), HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, Profile :: atom() | pid(), Opts :: [CookieHeaderOpt], CookieHeaderOpt :: {ipv6_host_with_brackets, boolean()}, Reason :: term().
返回使用配置文件 Profile
向 Url
发出请求时将发送的 Cookie 标头。如果未指定配置文件,则使用默认配置文件。
选项 ipv6_host_with_bracket
处理如何解析 IPv6 地址。有关详细信息,请参阅 request/4,5 的参数 Options
。
-spec get_options(OptionItems) -> {ok, Values} | {error, Reason} when OptionItems :: all | [OptionItem], OptionItem :: 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 :: [{OptionItem, term()}], Reason :: term().
等效于 get_options/2
。
-spec get_options(OptionItems, Profile) -> {ok, Values} | {error, Reason} when OptionItems :: all | [OptionItem], OptionItem :: 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 :: [{OptionItem, term()}], Profile :: atom() | pid(), Reason :: term().
检索客户端当前使用的选项。
等效于 info/1
。
生成杂项信息列表。用于调试。如果未指定配置文件,则使用默认配置文件。
-spec request(uri_string:uri_string()) -> {ok, Result} | {error, term()} when Result :: {StatusLine :: {HttpVersion, StatusCode, string()}, [HttpHeader], HttpBodyResult} | {StatusCode, HttpBodyResult} | RequestId | saved_to_file, HttpBodyResult :: uri_string:uri_string() | binary(), HttpVersion :: uri_string:uri_string(), StatusCode :: non_neg_integer(), HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, RequestId :: any().
等效于 request/2
。
-spec request(Url, Profile) -> {ok, Result} | {error, term()} when Url :: uri_string:uri_string(), Profile :: atom() | pid(), Result :: {StatusLine, [HttpHeader], HttpBodyResult} | {StatusCode, HttpBodyResult} | RequestId | saved_to_file, HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, HttpBodyResult :: uri_string:uri_string() | binary(), StatusLine :: {HttpVersion, StatusCode, string()}, HttpVersion :: uri_string:uri_string(), StatusCode :: non_neg_integer(), RequestId :: any().
-spec request(Method, Request, HttpOptions, Options) -> {ok, Result} | {error, term()} when Method :: head | get | put | patch | post | trace | options | delete, Request :: {uri_string:uri_string(), [HttpHeader]} | {uri_string:uri_string(), [HttpHeader], ContentType :: uri_string:uri_string(), HttpBody}, HttpBody :: iolist() | binary() | {fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}), Accumulator :: term()} | {chunkify, fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}), Accumulator :: term()}, HttpOptions :: [HttpOption], HttpOption :: {timeout, timeout()} | {connect_timeout, timeout()} | {ssl, [ssl:tls_option()]} | {autoredirect, boolean()} | {proxy_auth, {string(), string()}} | {version, HttpVersion} | {relaxed, boolean()}, Options :: [OptionRequest], OptionRequest :: {sync, boolean()} | {stream, StreamTo} | {body_format, BodyFormat} | {full_result, boolean()} | {headers_as_is, boolean()} | {socket_opts, [SocketOpt]} | {receiver, Receiver} | {ipv6_host_with_brackets, boolean()}, StreamTo :: none | self | {self, once} | file:name_all(), SocketOpt :: term(), BodyFormat :: string | binary, Receiver :: pid() | fun((term()) -> term()) | {ReceiverModule :: atom(), ReceiverFunction :: atom(), ReceiverArgs :: list()}, Result :: {StatusLine, [HttpHeader], HttpBodyResult} | {StatusCode, HttpBodyResult} | RequestId | saved_to_file, StatusCode :: non_neg_integer(), StatusLine :: {HttpVersion, StatusCode, string()}, HttpVersion :: uri_string:uri_string(), HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, HttpBodyResult :: uri_string:uri_string() | binary(), RequestId :: any().
等效于 request/5
。
-spec request(Method, Request, HttpOptions, Options, Profile) -> {ok, Result} | {error, term()} when Method :: head | get | put | patch | post | trace | options | delete, Request :: {uri_string:uri_string(), [HttpHeader]} | {uri_string:uri_string(), [HttpHeader], ContentType :: uri_string:uri_string(), HttpBody}, HttpBody :: iolist() | binary() | {fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}), Accumulator :: term()} | {chunkify, fun((Accumulator :: term()) -> eof | {ok, iolist(), Accumulator :: term()}), Accumulator :: term()}, HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, HttpOptions :: [HttpOption], HttpOption :: {timeout, timeout()} | {connect_timeout, timeout()} | {ssl, [ssl:tls_option()]} | {autoredirect, boolean()} | {proxy_auth, {string(), string()}} | {version, HttpVersion} | {relaxed, boolean()}, Options :: [OptionRequest], OptionRequest :: {sync, boolean()} | {stream, StreamTo} | {body_format, BodyFormat} | {full_result, boolean()} | {headers_as_is, boolean()} | {socket_opts, [SocketOpt]} | {receiver, Receiver} | {ipv6_host_with_brackets, boolean()}, StreamTo :: none | self | {self, once} | file:name_all(), BodyFormat :: string | binary, SocketOpt :: term(), Receiver :: pid() | fun((term()) -> term()) | {ReceiverModule :: atom(), ReceiverFunction :: atom(), ReceiverArgs :: list()}, Profile :: atom() | pid(), HttpVersion :: uri_string:uri_string(), Result :: {StatusLine, [HttpHeader], HttpBodyResult} | {StatusCode, HttpBodyResult} | RequestId | saved_to_file, StatusLine :: {HttpVersion, StatusCode, string()}, StatusCode :: non_neg_integer(), HttpBodyResult :: uri_string:uri_string() | binary(), RequestId :: any().
发送 HTTP 请求。该函数可以是同步的也可以是异步的。在后一种情况下,该函数返回 {ok, RequestId}
,然后根据该值将信息传递给 接收器
。
当 Profile
为 stand_alone
时,只能使用 pid。
HTTP 选项
timeout
- 请求的超时时间。当发送请求时,时钟开始计时。
时间以毫秒为单位。
默认值为
infinity
。connect_timeout
- 连接超时时间,在初始请求期间使用,当客户端连接到服务器时。时间以毫秒为单位。
默认值为选项
timeout
的值。ssl
- 这是SSL/TLS
连接配置选项。默认值通过调用
httpc:ssl_verify_host_options(true)
获取。 有关可用选项,请参阅 ssl:connect/2,3,4。autoredirect
- 客户端自动从新的 URI 检索信息,并将其作为结果返回,而不是 30X 结果代码。对于某些 30X 结果代码,不允许自动重定向。在这些情况下,始终返回 30X 结果。
默认值为
true
。proxy_auth
- 使用元组的代理授权标头,其中元组的第一个元素是username
,第二个元素是添加到请求的password
。version
- 可用于使客户端充当HTTP/1.0
客户端。默认情况下,这是一个HTTP/1.1
客户端。使用HTTP/1.0
时,不会使用持久连接。默认值为字符串
"HTTP/1.1"
。relaxed
- 如果设置为true
,则会启用针对已知服务器偏离 HTTP 标准的变通方法。默认值为
false
。
选项详细信息
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
。full_result
- 定义是否向调用方返回“完整结果”(即主体、标头和整个状态行),还是不返回(主体和状态代码)。默认值为
true
。headers_as_is
- 定义用户提供的标头是要转换为小写,还是被视为区分大小写。HTTP 标准要求它们不区分大小写。仅当没有其他方法与服务器通信或用于测试时才使用此功能。使用此选项时,不会自动添加任何标头。所有必要的标头都必须由用户提供。
默认值为
false
。socket_opts
- 用于此请求的套接字选项。覆盖函数 set_options 设置的任何值。
HTTP 客户端不检查选项的有效性,它们被假定为正确并传递给 ssl 应用程序和 inet 驱动程序,如果它们不正确,则可能会拒绝它们。
注意
设置
socket_opts
选项时不支持持久连接。当未设置socket_opts
时,当前实现假设对同一主机、端口组合的请求将使用相同的套接字选项。默认情况下,在建立连接时使用函数 set_options/1,2 设置的套接字选项。
receiver
- 定义客户端如何传递异步请求的结果(sync
的值为false
)。pid/0
- 消息以{http, ReplyInfo}
格式发送到此进程。alias/0
- 消息以{http, ReplyInfo}
格式发送到此特殊引用。function/1
- 通过调用提供的函数Receiver(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}
默认值是调用请求函数的进程的
pid
(self/0
)。ipv6_host_with_brackets
- 定义在解析带方括号的 IPv6 地址的 URI 的 Host-Port 部分时,是否保留这些方括号 (true
) 或将其删除 (false
)。默认值为
false
。
-spec reset_cookies() -> Void when Void :: term().
等效于 reset_cookies/1
。
重置(清除)指定 Profile
的 Cookie 数据库。如果未指定配置文件,则使用默认配置文件。
-spec set_options(Options) -> ok | {error, Reason} when 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} | {cookies, CookieMode} | {ipfamily, IpFamily} | {ip, IpAddress} | {port, Port} | {socket_opts, SocketOpts} | {verbose, VerboseMode} | {unix_socket, UnixSocket}, Proxy :: {HostName, Port}, Port :: non_neg_integer(), NoProxy :: [DomainDesc | HostName | IpAddressDesc], MaxSessions :: integer(), MaxKeepAlive :: integer(), KeepAliveTimeout :: integer(), MaxPipeline :: integer(), PipelineTimeout :: integer(), CookieMode :: enabled | disabled | verify, IpFamily :: inet | inet6 | local | inet6fb4, IpAddressDesc :: uri_string:uri_string(), IpAddress :: inet:ip_address(), VerboseMode :: false | verbose | debug | trace, SocketOpts :: [SocketOpt], SocketOpt :: term(), UnixSocket :: file:name_all(), Reason :: term(), DomainDesc :: string(), HostName :: uri_string:uri_string().
等效于 set_options/2
。
-spec set_options(Options, Profile) -> ok | {error, Reason} when 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} | {cookies, CookieMode} | {ipfamily, IpFamily} | {ip, IpAddress} | {port, Port} | {socket_opts, [SocketOpt]} | {verbose, VerboseMode} | {unix_socket, UnixSocket}, Profile :: atom() | pid(), SocketOpt :: term(), Proxy :: {HostName, Port}, Port :: non_neg_integer(), NoProxy :: [DomainDesc | HostName | IpAddressDesc], MaxSessions :: integer(), MaxKeepAlive :: integer(), KeepAliveTimeout :: integer(), MaxPipeline :: integer(), PipelineTimeout :: integer(), CookieMode :: enabled | disabled | verify, IpFamily :: inet | inet6 | local | inet6fb4, IpAddressDesc :: uri_string:uri_string(), IpAddress :: inet:ip_address(), VerboseMode :: false | verbose | debug | trace, UnixSocket :: string(), Reason :: term(), DomainDesc :: string(), HostName :: uri_string:uri_string().
设置用于后续请求的选项。
HostName
- 示例:“localhost”或“foo.bar.se”DomainDesc
- 示例"*.Domain"
或"*.ericsson.se"
IpAddressDesc
- 示例:“134.138”或“[FEDC:BA98”(所有以 134.138 或 FEDC:BA98 开头的 IP 地址),“66.35.250.150”或“[2010:836B:4179::836B:4179]”(完整的 IP 地址)。proxy
默认为{undefined, []}
,即未配置代理,并且https_proxy
默认为proxy
的值。MaxSessions
-MaxSessions
到主机的最大持久连接数。默认值为2
。MaxKeepAlive
-MaxKeepAlive
对同一主机连接的最大未完成请求数。默认值为5
。KeepAliveTimeout
-KeepAliveTimeout
如果持久连接空闲时间超过keep_alive_timeout
(以毫秒为单位),则客户端会关闭连接。服务器也可以有这样的超时时间,但不要想当然。默认值为120000
(= 2 分钟)。MaxPipeline
-MaxPipeline
在到主机的管道连接上的最大未完成请求数。默认值为2
。PipelineTimeout
-PipelineTimeout
如果持久连接空闲时间超过pipeline_timeout
(以毫秒为单位),则客户端会关闭连接。默认值为0
,这将导致不使用管道。CookieMode
- 如果启用了 cookie,则所有有效的 cookie 会自动保存在客户端管理器的 cookie 数据库中。如果使用verify
选项,则必须调用函数store_cookies/2
才能保存 cookie。默认值为disabled
。IpFamily
- 默认值为inet
。使用inet6fb4
选项,将优先使用 IPv6,但如果连接失败,将尝试进行 IPv4 回退连接。IpAddress
- 如果主机有多个网络接口,则此选项指定要使用哪个接口。有关详细信息,请参阅gen_tcp:connect/3,4
。Port
- 示例:8080
。要使用的本地端口号。有关详细信息,请参阅gen_tcp:connect/3,4
。SocketOpts
- 这些选项将附加到客户端使用的套接字选项。这些是在启动新的请求处理程序时(对于初始连接)的默认值。它们会直接传递给底层传输 (gen_tcp
或SSL
),而无需验证。VerboseMode
- 默认值为false
。此选项用于打开(或关闭)客户端上的不同级别的 Erlang 跟踪。它是一个调试功能。Profile
- 启动stand_alone
时,只能使用 pid。UnixSocket
- 用于通过 Unix 域套接字发送 HTTP 请求的实验性选项。unix_socket
的值应为具有 Erlang 进程的读/写权限的 Unix 域套接字文件的完整路径。默认值为undefined
。
注意
如果可能,客户端会保持其连接活动状态,并根据配置和当前情况使用带有或不带管道的持久连接。HTTP/1.1 规范没有提供关于在持久连接上发送多少请求是理想的指南。这很大程度上取决于应用程序。
长请求队列可能会导致用户感知到的延迟,因为较早的请求可能需要很长时间才能完成。HTTP/1.1 规范建议每个服务器限制为两个持久连接,这是
max_sessions
选项的默认值。当前实现假设对同一主机、端口组合的请求将使用相同的套接字选项。
返回可用于验证主机的 SSL 选项,使用 public_key:cacerts_get()
读取 CA 证书,如果 WildcardHostName
为 true,则将 public_key:public_key:pkix_verify_hostname_match_fun(https)
中的主机名检查添加到选项中。
-spec store_cookies(SetCookieHeaders, Url) -> ok | {error, Reason} when SetCookieHeaders :: [HttpHeader], HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, Url :: term(), Reason :: term().
等效于 store_cookies/3
。
-spec store_cookies(SetCookieHeaders, Url, Profile) -> ok | {error, Reason} when SetCookieHeaders :: [HttpHeader], HttpHeader :: {Field :: [byte()], Value :: binary() | iolist()}, Url :: term(), Profile :: atom() | pid(), Reason :: term().
将 SetCookieHeaders
中定义的 Cookie 保存在客户端配置文件 Cookie 数据库中。如果选项 cookies
设置为 verify
,则调用此函数。如果未指定配置文件,则使用默认配置文件。
-spec stream_next(Pid) -> ok when Pid :: pid().
触发要流式的下一条消息,即与套接字的活动行为相同。
-spec which_cookies() -> [CookieStores] when CookieStores :: {cookies, Cookies} | {session_cookies, Cookies}, Cookies :: [term()].
等效于 which_cookies/1
。
-spec which_cookies(Profile) -> [CookieStores] when Profile :: atom() | pid(), CookieStores :: {cookies, Cookies} | {session_cookies, Cookies}, Cookies :: [term()].
生成整个 Cookie 数据库的列表。用于调试/测试目的。如果未指定配置文件,则使用默认配置文件。
-spec which_sessions() -> SessionInfo when SessionInfo :: {GoodSession, BadSessions, NonSessions}, GoodSession :: [Session], BadSessions :: [term()], NonSessions :: [term()], Session :: term().
等效于 which_sessions/1
。
-spec which_sessions(Profile) -> SessionInfo when Profile :: atom() | pid(), SessionInfo :: {GoodSession, BadSessions, NonSessions}, GoodSession :: [Session], BadSessions :: [term()], NonSessions :: [term()], Session :: term().
此函数仅用于调试。它生成会话数据库的稍微处理的转储。会话信息元组的第一个列表将包含内部格式的会话信息。如果代码按预期工作,则会话信息元组的最后两个列表应始终为空。如果未指定配置文件,则使用默认配置文件。