在线文档教程

httpd

httpd

模块

httpd

模块摘要

HTTP 服务器 API

描述

HTTP 1.1 兼容的 Web 服务器的实现,如定义RFC 2616。提供 Web 服务器启动选项,管理功能和 Erlang 回调 API。

数据类型

在此模块中多次使用的类型定义:

boolean() = true | false

string()=ASCII 字符列表

path() = string()表示文件或目录路径

ip_address() = {N1,N2,N3,N4} % IPv4 | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6

hostname() = string() 代表主机,例如“foo.bar.com”

property() = atom()

Erlang http 服务器启动/停止

web 服务器可以被配置在启动时,开始Inets通过调用在运行时应用程序,或动态地Inets应用 API inets:start(httpd, ServiceConfig)inets:start(httpd, ServiceConfig, How),见inets(3)。配置选项也称为属性,如下所示:

文件属性

当 Web 服务器在应用程序启动时启动,性质是从一个配置文件可以由普通的 Erlang 属性列表的获取,也就是[{Option, Value}],其中Option = property()Value = term(),随后上了一个句号,或向后兼容,一个类似 Apache 的配置文件。如果 Web 服务器在运行时动态启动,则仍然可以指定文件,但也可以指定完整的属性列表。

{proplist_file,path()}

如果定义了此属性,则Inets希望查找此文件中定义的所有其他属性。该文件必须包含强制属性下列出的所有属性。

{文件路径()}

如果定义了该属性,则Inets希望找到此文件中定义的所有其他属性,该文件使用类似 Apache 的语法。该文件必须包含强制属性下列出的所有属性。类似 Apache 的语法是属性,写成一个单词,其中每个新单词以大写字母开头,后面跟着一个空格,然后是值,后面是一个新行。

示例:

{server_root, "/urs/local/www"} -> ServerRoot /usr/local/www

针对每个行为不同的属性记录了一些例外情况,特殊情况{directory, {path(), PropertyList}}{security_directory, {Dir, PropertyList}}表示如下:

<Directory Dir> <Properties handled as described above> </Directory>

注意

属性proplist_filefile相互排斥。也可能不支持类似 Apache 的选项那样更新的属性,这是一项遗留功能。

强制属性

{port,integer()}

HTTP 服务器收听的端口。如果将零指定为端口,则会选取任意可用端口,并使用函数httpd:info/2来确定选取哪个端口。

{server_name,string()}

您的服务器的名称,通常是完全合格的域名。

{server_root,path()}

定义服务器的主目录,其中可以存储日志文件等。其他属性中指定的相对路径引用此目录。

{document_root,path()}

定义 HTTP 服务器上可用文档的顶层目录。

通信属性

{bind_address,ip_address()| hostname()| 任何}

默认是any。在类似 Apache 的配置文件中any表示为*

{profile,atom()}

bind_addressport一起使用唯一标识 HTTP 服务器。这在虚拟化环境中非常有用,其中可以有多个具有相同 bind_address 和端口的服务器。如果此属性未明确设置,则假定该标识符bind_addressport唯一标识 HTTP 服务器。

{socket_type,ip_comm | {ip_comm,Config :: proplist()} | {essl,Config :: proplist()}}

有关ip_comm配置选项,请参阅gen_tcp:listen/2httpd 内部使用的一些选项无法设置。

有关SSL配置选项,请参阅ssl:listen/2

默认是ip_comm

{ipfamily,inet | INET6}

默认情况下inet,遗留选项inet6fb4不再有意义,并将转换为inet

{minimum_bytes_per_second,integer()}

如果给定,则为连接设置每秒最少字节数。

如果该值未获得,那么套接字将关闭以进行连接。

该选项对于降低“缓慢 DoS”攻击的风险很有帮助。

Erlang Web 服务器 API 模块

{modules,atom()}

定义 HTTP 服务器在处理请求时使用哪些模块。默认是[mod_alias, mod_auth, mod_esi, mod_actions, mod_cgi, mod_dir, mod_get, mod_head, mod_log, mod_disk_log]。注意有些mod模块依赖于其他模块,所以顺序不能完全随意。详细信息请参见Inets Web Server Modules用户指南。

限制属性

{customize,atom()}

一个回调模块来定制 inets HTTP 服务器的行为 httpd_custom_api

{disable_chunked_transfer_encoding_send,boolean()}

允许您在向 HTTP / 1.1 客户端发送响应时禁用分块传输编码。默认是false

{keep_alive,boolean()}

当客户端声称符合 HTTP / 1.1时,指示服务器是否使用持久连接。默认是true

{keep_alive_timeout,integer()}

服务器在关闭连接之前等待来自客户端的后续请求的秒数。默认是150

{max_body_size,integer()}

限制 HTTP 请求的消息正文的大小。默认是没有限制的。

{max_clients,integer()}

限制可支持的同时请求的数量。默认是150

{max_header_size,integer()}

限制 HTTP 请求的消息头的大小。默认是10240

{max_content_length,integer()}

传入请求中的最大内容长度(以字节为单位)。内容大于此的请求以状态413回答。默认值为100000000(100 MB)。

{max_uri_size,integer()}

限制 HTTP 请求 URI 的大小。默认是没有限制的。

{max_keep_alive_request,integer()}

客户端可以在一个连接上执行的请求数。当服务器响应定义的请求数时max_keep_alive_requests,服务器关闭连接。即使有排队的请求,服务器也会关闭它。默认是没有限制的。

{max_client_body_chunk,integer()}

强制将 HTTP PUT 或 POST 主体数据分块以传递给 mod_esi 回调。注意这不是 mod_cgi 支持的。默认是没有限制的,整个机构作为一个实体提供,这可能非常耗费内存。mod_esi(3)

管理属性

{mime_types,{MimeType,Extension} | 路径()}

MimeType = string()Extension = string()。传递到客户端的文件是根据 RFC 1590 MIME 类型。文件后缀在文件传递之前映射到 MIME 类型。文件后缀和 MIME 类型之间的映射可以指定为类似 Apache 的文件或直接在属性列表中指定。这样的文件可以看起来像下面这样:

# MIME type Extension text/html html htm text/plain asc txt

默认是{“html”,“text / html”},{“htm”,“text / html”}。

{mime_type,string()}

当要求服务器提供无法由 MIME 类型设置确定的文档类型时,服务器将使用此默认类型。

{server_admin,string()}

定义要包含在服务器返回的任何错误消息中的服务器管理员的电子邮件地址。

{server_tokens,none | prod | major | minor | minimal | os | full | {private,string()}}

定义服务器头的值的外观。

示例:假设版本Inets为5.8.1,服务器标记字符串对于不同的服务器标记值可以如下所示:

none

“”%服务器:标题将不会生成

prod

“inets”

major

“INTS/5”

minor

“inets / 5.8”

minimal

“inets / 5.8.1”

os

“inets / 5.8.1(unix)”

full

“inets / 5.8.1(unix / linux)OTP / R15B”

{private, "foo/bar"}

“foo/bar”

默认情况下,该值与之前一样,即minimal

{log_format,common | 合并}

定义是否根据common日志格式或扩展公用日志格式写入访问日志。该common格式是一行看起来像这样:remotehost rfc931 authuser [date] "request" status bytes

这里:

remotehost远程。rfc931客户端的远程用户名(RFC 931)。authuser用于身份验证的用户名。[date]请求的日期和时间(RFC 1123)。"request"请求行来自客户端(RFC 1945)。statusHTTP状态码返回给客户端(RFC 1945)。bytes传送文件的内容长度。

combined格式一行看起来像这样:remotehost rfc931 authuser [date] "request" status bytes "referer" "user_agent"

除了早些时候:

"referer"在请求 URL 之前客户端所在的URL(如果无法确定,则在此字段中放置一个减号)。"user_agent"客户声称使用的软件(如果无法确定,则在此字段中放置一个减号)。

这会影响由mod_logmod_disk_log写入的访问日志。

{error_log_format,漂亮| 紧凑}

默认是pretty。如果错误日志是要被人直接读取的,那么这pretty是最好的选择。

pretty 有一个格式对应于:

io:format("[~s] ~s, reason: ~n ~p ~n~n", [Date, Msg, Reason]).

compact 有一个格式对应于:

io:format("[~s] ~s, reason: ~w ~n", [Date, Msg, Reason]).

这会影响由mod_logmod_disk_log写入的错误日志。

URL 别名属性 - 需要 mod_alias

{别名,{别名,RealName}}

Alias = string()RealName = string()alias允许将文档存储在本地文件系统中而不是document_root位置。以 url-path 开头的 URL 被映射到以 directory-filename 开头的本地文件,例如:

{alias, {"/image", "/ftp/pub/image"}}

访问http://your.server.org/image/foo.gif会引用文件/ftp/pub/image/foo.gif。

{re_write,{Re,Replacement}}

Re = string()Replacement = string()re_write允许将文档存储在本地文件系统中而不是document_root位置。通过重写 URL 来re:replace/3在本地文件系统中生成路径,例如:

{re_write, {"^/[~]([^/]+)(.*)$", "/home/\\1/public\\2"}}

访问 http://your.server.org/~bob/foo.gif 会引用文件/home/bob/public/foo.gif。在类似Apache的配置文件中,使用单个空格进行Re分隔Replacement,并且预期的反斜杠不需要反斜杠转义,相同的示例将变为:

ReWrite ^/[~]([^/]+)(.*)$ /home/\1/public\2

谨防尾随空间Replacement被使用。如果您必须有空格Re,请使用字符编码\040re(3)

{directory_index,string()}

directory_index指定资源列表以查找客户机是否/在目录名称末尾使用a来请求目录。file描述目录中文件的名称。可以给出几个文件,在这种情况下,服务器返回找到的第一个文件,例如:

{directory_index, ["index.html", "welcome.html"]}

CGI 属性 - 需要 mod_cgi

{script_alias,{别名,RealName}}

Alias = string()RealName = string()alias除了它们也将目标目录标记为包含 CGI 脚本之外,它们与属性具有相同的行为。以 url-path 开头的 URL 被映射到以 directory-filename 开头的脚本,例如:

{script_alias, {"/cgi-bin/", "/web/cgi-bin/"}}

{script_re_write,{Re,Replacement}}

Re = string()Replacement = string()re_write除了它们也将目标目录标记为包含CGI脚本之外,它们与属性具有相同的行为。以url-path开头的URL被映射到以directory-filename开头的脚本,例如:

{script_re_write, {"^/cgi-bin/(\\d+)/", "/web/\\1/cgi-bin/"}}

{script_nocache,boolean()}

如果script_nocache设置为true,HTTP 服务器默认添加必要的头字段,以防止代理缓存页面。通常这是优选的。默认为false

{script_timeout,integer()}

Web 服务器在脚本中每个数据块之间等待的时间(秒)。如果 CGI 脚本在超时之前未提供任何数据,则关闭与客户端的连接。默认是15

{action,{MimeType,CgiScript}} - 需要 mod_action

MimeType = string()CgiScript = string()action每当请求某个 MIME 类型的文件时,都会添加一个激活 CGI 脚本的操作。它使用标准 CGI PATH_INFO 和 PATH_TRANSLATED 环境变量传播所请求文档的 URL 和文件路径。

示例:

{action, {"text/plain", "/cgi-bin/log_and_deliver_text"}}

{script,{Method,CgiScript}} - 需要 mod_action

Method = string()CgiScript = string()script每当使用特定的 HTTP 方法请求文件时,添加一个激活 CGI 脚本的动作。该方法是 GET 或 POST,如定义RFC 1945。它使用标准 CGI PATH_INFO 和 PATH_TRANSLATED 环境变量传播所请求文档的 URL 和文件路径。

示例:

{script, {"PUT", "/cgi-bin/put"}}

ESI 属性 - 需要 mod_esi

{erl_script_alias,{URLPath,AllowedModule}}

URLPath = string()AllowedModule = atom()erl_script_alias将所有匹配 url-path 的 URL 标记为 erl scheme 脚本。匹配的 URL 被映射到特定的模块和功能,例如:

{erl_script_alias, {"/cgi-bin/example", [httpd_example]}}

{erl_script_nocache,boolean()}

如果erl_script_nocache设置为true,服务器将添加HTTP头字段,以防止代理缓存页面。对于动态内容而言,这通常是一个好主意,因为每个请求之间的内容经常不同。默认是false

{erl_script_timeout,integer()}

如果erl_script_timeout设置以秒为单位的时间,服务器将在每个要传递的数据块之间等待mod_esi:deliver/2。默认是15。这只与使用 erl 方案的脚本相关。

{eval_script_alias,{URLPath,AllowedModule}}

URLPath = string()AllowedModule = atom()。与erl_script_alias使用eval方案的脚本相同。这仅支持向后兼容。评估方案已弃用。

日志属性 - 需要 mod_log

{error_log,path()}

定义用于记录服务器错误的错误日志文件的文件名。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

{security_log,path()}

定义用于记录安全事件的访问日志文件的文件名。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

{transfer_log,path()}

定义用于记录传入请求的访问日志文件的文件名。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

磁盘日志属性 - 需要 mod_disk_log

{disk_log_format,内部| 外部}

定义日志文件的文件格式。详情请参阅disk_log。如果使用内部文件格式,则会在崩溃后修复日志文件。当日志文件被修复时,数据可能会消失。使用外部文件格式时,httpd如果日志文件损坏,则不启动。默认是external

{error_disk_log,path()}

定义disk_log(3)用于记录服务器错误的()错误日志文件的文件名。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

{error_disk_log_size,{MaxBytes,MaxFiles}}

MaxBytes = integer()MaxFiles = integer()。定义(disk_log(3))错误日志文件的属性。该文件的类型为换行日志,最大字节数写入每个文件,在第一个文件被截断并重用之前使用最大文件数。

{security_disk_log,path()}

定义disk_log(3)记录传入安全事件的()访问日志文件的文件名,即已认证的请求。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

{security_disk_log_size,{MaxBytes,MaxFiles}}

MaxBytes = integer()MaxFiles = integer()。定义disk_log(3)访问日志文件的属性。该文件的类型为换行日志,最大字节数写入每个文件,在第一个文件被截断并重用之前使用最大文件数。

{transfer_disk_log,path()}

定义disk_log(3)记录传入请求的()访问日志文件的文件名。如果文件名不以斜杠(/)开头,则认为它是相对于server_root

{transfer_disk_log_size,{MaxBytes,MaxFiles}}

MaxBytes = integer()MaxFiles = integer()。定义disk_log(3)访问日志文件的属性。该文件的类型为换行日志,最大字节数写入每个文件,在第一个文件被截断并重用之前使用最大文件数。

认证属性 - 需要 mod_auth

{directory,{path(),{property(),term()}}}

目录的属性如下:

{allow_from,all | RegxpHostString}

定义一组被授予对给定目录的访问权限的主机,例如:

{allow_from, ["123.34.56.11", "150.100.23"]}

主人123.34.56.11所有的机器150.100.23子网允许访问。

{deny_from,全部| RegxpHostString}

定义一组要拒绝访问给定目录的主机,例如:

{deny_from, ["123.34.56.11", "150.100.23"]}

主机123.34.56.11150.100.23子网上的所有机器都不允许访问。

{auth_type,plain | dets | Mnesia的}

设置用于该目录的认证数据库的类型。不同方法之间的主要区别在于,当使用 Mnesia 和 Dets 时可以保存动态数据。这个属性AuthDbType在类 Apache 的配置文件中被调用。

{auth_user_file,path()}

设置包含用户认证用户和密码列表的文件的名称。文件名可以是绝对的或相对的server_root。如果使用普通存储方法,则该文件是纯文本文件,其中每行包含一个用户名,后跟一个冒号,后跟未加密的密码。如果用户名重复,则行为未定义。

示例:

ragnar:s7Xxv7 edward:wwjau8

如果使用 Dets 存储方法,则用户数据库由 Dets 维护,不得手动编辑。使用模块中的 API 函数mod_auth来创建/编辑用户数据库。如果使用 Mnesia 存储方法,该指令将被忽略。出于安全原因,请确保它auth_user_file存储在 Web 服务器的文档树之外。如果它被放置在它所保护的目录中,客户端可以下载它。

{auth_group_file,path()}

设置包含用户组认证用户组列表的文件的名称。文件名可以是绝对的或相对的server_root。如果使用普通存储方法,则组文件是纯文本文件,其中每行包含一个组名,后跟一个冒号,然后是用空格分隔的成员用户名。

示例:

group1: bob joe ante

如果使用 Dets 存储方法,则组数据库由 Dets 维护,不得手动编辑。使用模块的 API mod_auth创建/编辑组数据库。如果使用 Mnesia 存储方法,该指令将被忽略。出于安全原因,请确保auth_group_file该文件存储在 Web 服务器的文档树之外。如果它被放置在它所保护的目录中,客户端可以下载它。

{auth_name,string()}

设置目录的授权领域(auth-domain)的名称。该字符串通知客户端使用哪个用户名和密码。

{auth_access_password,string()}

如果设置为“NoPassword”以外,则所有 API 调用都需要密码。如果密码设置为“DummyPassword”,则密码必须在任何其他API调用之前更改。为了确保验证数据的安全,必须在 Web 服务器启动后更改密码。否则它会在配置文件中以明文形式写入。

{require_user,string()}

定义用户使用秘密密码授予对给定目录的访问权限。

{require_group,string()}

定义用户使用秘密密码授予对给定目录的访问权限。

Htaccess 认证属性 - 需要 mod_htaccess

{access_files,path()}

指定用于访问文件的文件名。当一个请求到达时,被请求资源的路径中的每个目录都将在文件之后被搜索,该文件的名称由该参数指定。如果找到这样的文件,则解析该文件,并将其中指定的限制应用于该请求。

安全属性 - 需要 mod_security

{security_directory,{path(),{property(),term()}}}

安全目录的属性如下所示:

{data_file,path()}

安全数据文件的名称。文件名可以是绝对的,也可以是相对于server_root此文件用于存储模块的持久数据。mod_security...

{max_retries,integer()}

指定在用户被阻止之前尝试对用户进行身份验证的最大次数。如果用户在被阻止时成功进行身份验证,则用户将从服务器收到403(禁止)响应。如果用户在被阻止时尝试失败,服务器将返回401(未授权),出于安全原因。默认是3。可以设置为无限。

{block_time,integer()}

指定用户被阻止的分钟数。这段时间过后,用户会自动重新获得访问权限。默认是60

{fail_expire_time,integer()}

指定记录失败用户身份验证的分钟数。如果用户在这段时间过去之后进行身份验证,则以前失败的身份验证将被遗忘。默认是30

{auth_timeout,integer()}指定成功记录用户身份验证的秒数。这段时间过后,认证不再被报告。默认是30

出口

info(Pid) ->info(Pid, Properties) -> [{Option, Value}]

类型

获取有关 HTTP 服务器的信息。只用 pid 调用时,所有属性都会被提取。当用特定属性列表调用时,它们被提取。可用的属性与服务器的启动选项相同。

注意

Pid 是从 Pid 返回的 Pid inets:start/[2,3]。也可以检索窗体inets:services/0inets:services_info/0查看inets(3)

info(Address, Port) ->info(Address, Port, Profile) ->info(Address, Port, Profile, Properties) -> [{Option, Value}]info(Address, Port, Properties) -> [{Option, Value}]

类型

获取有关 HTTP 服务器的信息。如果只叫AddressPort,所有属性被取出。当用特定属性列表调用时,它们被提取。可用的属性与服务器的启动选项相同。

注意

地址必须是 IP 地址,不能是主机名。

reload_config(Config, Mode) -> ok | {error, Reason}

类型

重新加载 HTTP 服务器配置而不重新启动服务器。传入的请求在重新载入时间期间以临时关闭消息回答。

注意

可用属性是一样的服务器的启动选项,但性能bind_addressport不能更改。

如果模式受到干扰,则服务器会被强制阻止,所有正在进行的请求都将终止,并立即开始重新加载。如果模式不受干扰,则不会接受新连接,但在重新加载完成之前允许正在进行的请求完成。

Erlang Web 服务器 API 数据类型

Erlang Web 服务器 API 数据类型如下所示:

ModData = #mod{} -record(mod, { data = [], socket_type = ip_comm, socket, config_db, method, absolute_uri, request_uri, http_version, request_line, parsed_header = [], entity_body, connection }).

要在回调模块中使用以下记录:

-include_lib("inets/include/httpd.hrl").

记录的字段mod具有以下含义:

data

Type [{InteractionKey,InteractionValue}]用于在模块之间传播数据。interaction_data()在函数类型声明中描述。

socket_type

socket_type()指示它是 IP 套接字还是ssl套接字。

socket

套接字,格式ip_commssl取决于socket_type

config_db

配置文件指令作为键值元组存储在 ETS 表中。config_db()在函数类型声明中描述。

method

键入"GET" | "POST" | "HEAD" | "TRACE",即 HTTP 方法。

absolute_uri

如果请求是 HTTP / 1.1请求,则 URI 可以是绝对 URI 格式。在这种情况下,请httpd在此字段中保存绝对 URI。一个绝对 URI 的例子是"http://ServerName:Part/cgi-bin/find.pl?person=jocke"

request_uri

Request-URI在所定义的RFC 1945,例如,"/cgi-bin/find.pl?person=jocke"

http_version

请求的HTTP版本,即“HTTP / 0.9”,“HTTP / 1.0”或“HTTP / 1.1”。

request_line

Request-Line在所定义的RFC 1945,例如,"GET /cgi-bin/find.pl?person=jocke HTTP/1.0"

parsed_header类型[{HeaderKey,HeaderValue}]parsed_header包含存储在列表中的 HTTP 请求中的所有 HTTP 头字段作为键值元组。查看RFC 2616所有标题字段的列表。例如,日期字段存储为{"date","Wed, 15 Oct 1997 14:35:17 GMT"}RFC 2616 定义了 HTTP 是不区分大小写的协议,并且头字段可以是小写或大写。httpd确保所有标题字段名称均为小写。entity_body

entity-Body如在定义RFC 2616中,例如,从使用 POST 方法 CGI 脚本发送的数据。

connection

true | false。如果设置为true,与客户端的连接是持久连接,并且在请求被提供时不会关闭。

Erlang web 服务器 api 回调函数

出口

Module:do(ModData)-> {proceed, OldData} | {proceed, NewData} | {break, NewData} | done

类型

当有效的请求到达时httpd,它会do/1在每个模块中调用,由其配置选项定义Module。该功能可以为其他模块生成数据或者可以将其发送回客户端的响应。

该领域dataModData是一个列表。该列表是从上次呼叫返回的列表do/1

Body是发送回客户端的 HTTP 响应的主体。消息后附加一个适当的头文件。StatusCode是响应的状态代码,请参阅RFC 2616适当的值。

Head是 HTTP 头字段的关键值列表。服务器从这个数据构造一个 HTTP 头。请参阅RFC 2616每个标题字段的适当值。如果客户端是 HTTP / 1.0 客户端,则服务器将对列表进行过滤,以便仅将 HTTP / 1.0 头字段发送回客户端。

如果Body返回,并等于{Fun,Arg},Web 服务器将尝试apply/2FunArg作为参数。Web 服务器期望乐趣返回一个(Body)HTTP repsonse 列表,或者sentHTTP 响应被发送回客户端的原子。如果close从乐趣中返回,则出现问题,并且服务器通过关闭连接将其发送给客户端。

Module:load(Line, AccIn)-> eof | ok | {ok, AccOut} | {ok, AccOut, {Option, Value}} | {ok, AccOut, [{Option, Value}]} | {error, Reason}

类型

将类似 Apache 的配置文件中的行转换为{Option, Value}元组。一些更复杂的配置选项,比如directorysecurity_directory创建一个累加器。这个函数只需要这个特定回调模块实现的选项的子句。

Module:remove(ConfigDB) -> ok | {error, Reason}

类型

httpd关闭时,它会尝试执行remove/1每个 Erlang 的 Web 服务器回调模块中。程序员可以使用这个函数来清理在存储函数中创建的资源。

Module:store{Option, Value}, Config)-> {ok, {Option, NewValue}} | {error, Reason}

类型

在将它们保存到内部数据库之前检查配置选项的有效性。此功能也可能有副作用,即设置配置选项隐含的必要额外资源。它还可以通过更改选项的值来解决配置选项之间可能存在的依赖关系。这个函数只需要这个特定回调模块实现的选项的子句。

Erlang web 服务器 api 帮助功能

出口

parse_query(QueryString) -> [{Key,Value}]

类型

parse_query/1传入的数据解析到erleval脚本(见mod_esi(3))在标准URL格式定义的,即,“+”变为“空间”和十六进制字符解码(%xx)。

另见

RFC 2616inets(3)ssl(3)