我有一个TIdHttpServer应用程序。我有一个带有特殊字符的简单html文档:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>This is the title</title>
</head>
<body>
<form method="post">
<p>
<input name="name" value="Все данные по веб-сайту" />
<input type="submit" value="submit" />
</p>
</form>
</body>
</html>
我提供此页面并处理帖子。我的“获取”代码如下。问题是我无法正确解码%hh 数据。
procedure TForm3.Get(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
mFileName: String;
txtFile: TextFile;
begin
if ARequestInfo.Params.values['name']<>'' then begin
AssignFile( txtFile , ChangeFileExt(ParamStr(0),'.log') );
Append( TxtFile );
WriteLn(TxtFile,'Unparsed:'+ARequestInfo.UnparsedParams);
WriteLn(TxtFile,'Parsed:'+ARequestInfo.Params.values['name']);
MyDecodeAndSetParams(ARequestInfo);
WriteLn(TxtFile,'Decoded:'+ARequestInfo.Params.values['name']);
System.Close( TxtFile );
end ;
mFileName := ExtractFileDir(ParamStr(0))+'\inputform.txt';
AResponseInfo.ContentStream := TFileStream.Create(mFileName, fmOpenRead);
end;
MyDecodeAndSetParams 功能:
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);
if ARequestInfo.CharSet <> '' then
LEncoding := CharsetToEncoding(ARequestInfo.CharSet)
else
LEncoding := IndyTextEncoding_UTF8;
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;
我的文件中的输出如下:
Unparsed:name=%D0%92%D1%81%D0%B5+%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5+%D0%BF%D0%BE+%D0%B2%D0%B5%D0%B1-%D1%81%D0%B0%D0%B9%D1%82%D1%83
Parsed:οсе даннϿе по веб-сайϿϿ
Decoded:οсе даннϿе по веб-сайϿϿ
我可以使用this decoder获取Unparsed数据并对其进行解码,并正确返回字符串:
Вседанныеповеб-сайту
我需要做什么才能将params正确解码为表单上的内容?
答案 0 :(得分:5)
如果AResponseInfo.CharSet
为空(因为客户端没有在HTTP Content-Type
标头中发送字符集),CharsetToEncoding('')
将返回Indy的本地8位字符集而不是UTF-8。这就是为什么你的数据没有被正确解码的原因。
对于application/x-www-form-urlencoded
,字符集并不总是在HTTP标头中发送,因为客户端可能会认为服务器根据它发送HTML的字符集知道所期望的字符集。客户端也可能可能会在已发布的表单数据中发送字符集,例如在_charset_
字段中。
尝试更改此内容:
LEncoding := CharsetToEncoding(ARequestInfo.CharSet);
对此:
if ARequestInfo.CharSet <> '' then
LEncoding := CharsetToEncoding(ARequestInfo.CharSet)
else
LEncoding := IndyTextEncoding_UTF8;
这样,除非客户端发送显式字符集,否则默认为UTF-8。
更新:如果您使用的是Unicode前版本的Delphi(2007或更早版本),Indy会使用AnsiString
代替UnicodeString
,因此TIdURI.URLDecode()
将首先使用指定的AByteEncoding
参数将输入解码为Unicode(如果未指定,则默认为IndyTextEncoding_UTF8
),然后使用指定的ADestEncoding
参数将Unicode数据转换为ANSI(默认值)如果没有指定,则IndyTextEncoding_OSDefault
。
您在解码为UTF-8时已经显示正确解码为Unicode的俄语输入,但如果您的代码在运行的机器上运行,则在转换为ANSI期间很容易丢失字符(将它们转换为'?'
)不要在OS层使用俄语字符集,例如ISO-8859-5或KOI8-R。
为确保正确的转换,您必须在这些计算机上指定所需的AnsiString
编码,例如:
var
LEncoding, LAnsiEncoding: IIdTextEncoding;
...
LEncoding := IndyTextEncoding_UTF8;
LAnsiEncoding := CharsetToEncoding('ISO-8859-5'); // or 'KOI8-R', etc
...
ARequestInfo.Params.Add(TIdURI.URLDecode(s, LEncoding, LAnsiEncoding));
在Unicode版本的Delphi(2009及更高版本)中,Indy使用UnicodeString
代替AnsiString
,因此不存在ADestEncoding
参数。