【发布时间】:2014-07-21 09:32:18
【问题描述】:
当 Indy HTTP 服务器收到带有 /find?location=%D1%82%D0%B5%D1%81%D1%82(utf-8 url 编码值)之类 url 的请求时,“location”字段在requestinfo 的 Params 具有不可读的值 ÑеÑÑ。
如何获得可读值? Indy HTTPServer 版本 10.6.0.4975
【问题讨论】:
当 Indy HTTP 服务器收到带有 /find?location=%D1%82%D0%B5%D1%81%D1%82(utf-8 url 编码值)之类 url 的请求时,“location”字段在requestinfo 的 Params 具有不可读的值 ÑеÑÑ。
如何获得可读值? Indy HTTPServer 版本 10.6.0.4975
【问题讨论】:
TIdHTTPServer 当前使用Content-Type 请求标头中指定的字符集解析输入参数,如果没有指定字符集,则使用 Indy 的 8 位编码。这是TIdHTTPServer 的已知限制,因为目前没有选项告诉它使用用户定义的字符集解码参数。因此,您将不得不手动解析ARequestInfo.QueryParams 和/或ARequestInfo.UnparsedParams 属性,例如通过在其AByteEncoding 参数中使用UTF-8 编码直接调用TIdURI.URLDecode(),例如:
procedure MyDecodeAndSetParams(ARequestInfo: TIdHTTPRequestInfo);
var
i, j : Integer;
value: s: string;
LEncoding: IIdTextEncoding;
begin
if IsHeaderMediaType(ARequestInfo.ContentType, 'application/x-www-form-urlencoded') then
begin
value := ARequestInfo.FormParams;
LEncoding := CharsetToEncoding(ARequestInfo.CharSet);
end else
begin
value := ARequestInfo.QueryParams;
LEncoding := IndyTextEncoding_UTF8;
end;
ARequestInfo.Params.BeginUpdate;
try
ARequestInfo.Params.Clear;
i := 1;
while i <= Length(value) do
begin
j := i;
while (j <= Length(value)) and (value[j] <> '&') do
begin
Inc(j);
end;
s := StringReplace(Copy(value, i, j-i), '+', ' ', [rfReplaceAll]);
ARequestInfo.Params.Add(TIdURI.URLDecode(s, LEncoding));
i := j + 1;
end;
finally
ARequestInfo.Params.EndUpdate;
end;
end;
procedure TForm1.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
MyDecodeAndSetParams(ARequestInfo);
...
end;
更新:自 2021 年 2 月起,如果 Content-Type 标头中未指定字符集,TIdHTTPServer 现在默认使用 UTF-8 解析输入参数。因此不再需要上述解决方法。
【讨论】:
CharsetToEncoding()(DecodeAndSetParams() 在内部使用)强制 8 位作为空白字符集,而不是使用GIdDefaultTextEncoding。我已经相应地更新了我的答案。