如何阻止 Indy 将 XML 中的字符转换为代码
How to stop Indy from converting characters in XML to codes
我正在尝试使用第三方网站 API,它希望请求正文是 XML 文档,但服务器接收的 XML 是由于格式不正确而被拒绝,因为 Indy 已经用 ANSI 代码替换了一堆字符。
我正在使用 XE2 和 Indy 10.5.8.0。
我已经注意到 Indy 正在将 CRLF 转换为 &,因此将所有这些都从源代码中删除 XML。现在,当我传递给 .Post 的 TStringList 包含:
<?xml version="1.0" encoding="utf-8"?><AdCourierAPI>
服务器正在查看:
%3C%3Fxml+version=%221.0%22+encoding%3D%22utf-8%22%3F%3E%3CAdCourierAPI%3E
如何阻止 Indy 这样做?我需要更改编码吗?
这里是 API 方法之一的代码:
function TBroadBeanAPI.ListChannels(const AUserName, APassword: String): String;
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
ASource: TStringList;
XMLRequest: String;
begin
HTTP := TIdHTTP.Create(nil);
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
ASource := TStringList.Create;
Result := '';
try
HTTP.IOHandler := SSL;
HTTP.Request.ContentType := 'text/xml';
HTTP.Request.Charset := 'utf-8';
XMLRequest := '<?xml version="1.0" encoding="utf-8"?>'+
'<AdCourierAPI>'+
' <Method>ListChannels</Method>'+
' <APIKey>'+APIKEY+'</APIKey>'+
' <Account>'+
' <UserName>'+AUserName+'</UserName>'+
' <Password>'+APassword+'</Password>'+
' </Account>'+
'</AdCourierAPI>';
ASource.Text := XMLRequest;
Result := HTTP.Post(APIURL, ASource);
finally
SSL.Free;
HTTP.Free;
ASource.Free;
end;
end;
答案是关闭TIdHTTP对象的HTTPOptions中的[hoForceEncodeParams]。可以这样做:
HTTP.HTTPOptions := [];
您一开始就使用了错误的 Post()
版本。
您正在使用接受 TStrings
作为输入的 Post()
的重载版本。该版本旨在以 application/x-www-form-urlencoded
格式发布 HTML 网络表单,其中 TStrings
应包含 name=value
字符串,这些字符串根据 W3C 提交网络表单的规则进行编码。这就是为什么您会看到 XML 按原样编码的原因。
您需要使用接受 TStream
作为输入的 Post()
的另一个重载版本。 TStream
数据将按原样传输。
试试这个:
function TBroadBeanAPI.ListChannels(const AUserName, APassword: String): String;
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
ASource: TStringStream;
XMLRequest: String;
begin
Result := '';
HTTP := TIdHTTP.Create(nil);
try
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
HTTP.IOHandler := SSL;
HTTP.Request.ContentType := 'text/xml';
HTTP.Request.Charset := 'utf-8';
XMLRequest := '<?xml version="1.0" encoding="utf-8"?>'+
'<AdCourierAPI>'+
' <Method>ListChannels</Method>'+
' <APIKey>'+APIKEY+'</APIKey>'+
' <Account>'+
' <UserName>'+AUserName+'</UserName>'+
' <Password>'+APassword+'</Password>'+
' </Account>'+
'</AdCourierAPI>';
ASource := TStringStream.Create(XMLRequest, TEncoding.UTF8);
try
Result := HTTP.Post(APIURL, ASource);
finally
ASource.Free;
end;
finally
HTTP.Free;
end;
end;
附带说明一下,您在构建 XML 时并未对 APIKEY
、AUserName
或 APassword
进行编码。如果它们包含保留字符,则根据 XML 格式规则,它们必须 escaped/encoded。所以要当心。您应该使用真正的 XML 引擎来构建您的 XML,而不是使用字符串连接。否则,至少添加一个 XML 兼容的编码函数,以便您可以连接正确格式的字符串。
我正在尝试使用第三方网站 API,它希望请求正文是 XML 文档,但服务器接收的 XML 是由于格式不正确而被拒绝,因为 Indy 已经用 ANSI 代码替换了一堆字符。
我正在使用 XE2 和 Indy 10.5.8.0。
我已经注意到 Indy 正在将 CRLF 转换为 &,因此将所有这些都从源代码中删除 XML。现在,当我传递给 .Post 的 TStringList 包含:
<?xml version="1.0" encoding="utf-8"?><AdCourierAPI>
服务器正在查看:
%3C%3Fxml+version=%221.0%22+encoding%3D%22utf-8%22%3F%3E%3CAdCourierAPI%3E
如何阻止 Indy 这样做?我需要更改编码吗?
这里是 API 方法之一的代码:
function TBroadBeanAPI.ListChannels(const AUserName, APassword: String): String;
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
ASource: TStringList;
XMLRequest: String;
begin
HTTP := TIdHTTP.Create(nil);
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
ASource := TStringList.Create;
Result := '';
try
HTTP.IOHandler := SSL;
HTTP.Request.ContentType := 'text/xml';
HTTP.Request.Charset := 'utf-8';
XMLRequest := '<?xml version="1.0" encoding="utf-8"?>'+
'<AdCourierAPI>'+
' <Method>ListChannels</Method>'+
' <APIKey>'+APIKEY+'</APIKey>'+
' <Account>'+
' <UserName>'+AUserName+'</UserName>'+
' <Password>'+APassword+'</Password>'+
' </Account>'+
'</AdCourierAPI>';
ASource.Text := XMLRequest;
Result := HTTP.Post(APIURL, ASource);
finally
SSL.Free;
HTTP.Free;
ASource.Free;
end;
end;
答案是关闭TIdHTTP对象的HTTPOptions中的[hoForceEncodeParams]。可以这样做:
HTTP.HTTPOptions := [];
您一开始就使用了错误的 Post()
版本。
您正在使用接受 TStrings
作为输入的 Post()
的重载版本。该版本旨在以 application/x-www-form-urlencoded
格式发布 HTML 网络表单,其中 TStrings
应包含 name=value
字符串,这些字符串根据 W3C 提交网络表单的规则进行编码。这就是为什么您会看到 XML 按原样编码的原因。
您需要使用接受 TStream
作为输入的 Post()
的另一个重载版本。 TStream
数据将按原样传输。
试试这个:
function TBroadBeanAPI.ListChannels(const AUserName, APassword: String): String;
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
ASource: TStringStream;
XMLRequest: String;
begin
Result := '';
HTTP := TIdHTTP.Create(nil);
try
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
HTTP.IOHandler := SSL;
HTTP.Request.ContentType := 'text/xml';
HTTP.Request.Charset := 'utf-8';
XMLRequest := '<?xml version="1.0" encoding="utf-8"?>'+
'<AdCourierAPI>'+
' <Method>ListChannels</Method>'+
' <APIKey>'+APIKEY+'</APIKey>'+
' <Account>'+
' <UserName>'+AUserName+'</UserName>'+
' <Password>'+APassword+'</Password>'+
' </Account>'+
'</AdCourierAPI>';
ASource := TStringStream.Create(XMLRequest, TEncoding.UTF8);
try
Result := HTTP.Post(APIURL, ASource);
finally
ASource.Free;
end;
finally
HTTP.Free;
end;
end;
附带说明一下,您在构建 XML 时并未对 APIKEY
、AUserName
或 APassword
进行编码。如果它们包含保留字符,则根据 XML 格式规则,它们必须 escaped/encoded。所以要当心。您应该使用真正的 XML 引擎来构建您的 XML,而不是使用字符串连接。否则,至少添加一个 XML 兼容的编码函数,以便您可以连接正确格式的字符串。