当responseText包含有效的Xml时,IXMLHttpRequest.responseXml为空,没有解析错误

Ian*_*oyd 7 xml delphi xmlhttprequest serverxmlhttp delphi-5

我从政府网站上获取一些XML :

http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml
Run Code Online (Sandbox Code Playgroud)

我正在使用以下相当简单的代码:

var
   szUrl: string;
   http: IXMLHTTPRequest;
begin
   szUrl := 'http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml';

   http := CoXMLHTTP60.Create;
   http.open('GET', szUrl, False, '', '');
   http.send(EmptyParam);

   Assert(http.Status = 200);

   Memo1.Lines.Add('HTTP/1.1 '+IntToStr(http.status)+' '+http.statusText);
   Memo1.Lines.Add(http.getAllResponseHeaders);
   Memo1.Lines.Add(http.responseText);
Run Code Online (Sandbox Code Playgroud)

我不会显示返回的所有正文,但它确实返回有效的xml responseText:

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3


<?xml version="1.0" encoding="ISO-8859-1"?>
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns="http://purl.org/rss/1.0/"
    xmlns:cb="http://www.cbwiki.net/wiki/index.php/Specification_1.1"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:dcterms="http://purl.org/dc/terms/"
    xmlns:xsi="http://www.w3c.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.w3c.org/1999/02/22-rdf-syntax-ns#rdf.xsd">
    <channel rdf:about="http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_ALL.xml">
        <title xml:lang="en">Bank of Canada: Noon Foreign Exchange Rates</title>
        <link>http://www.bankofcanada.ca/rates/exchange/noon-rates-5-day/</link>
Run Code Online (Sandbox Code Playgroud)

好的,很好,那里有有效的xml.我知道这是有效的,因为......好好看看它.但我也知道通过解析它是有效的:

var
   ...
   szXml: WideString;
   doc: DOMDocument60;
begin
   ...
   szXml := http.responseText;

   doc.loadXML(szXml);
   Assert(doc.parseError.errorCode = 0);

   Memo1.Lines.Add('============parsed xml');
   Memo1.Lines.Add(doc.xml);
Run Code Online (Sandbox Code Playgroud)

起源IXmlHttpRequest包含一个responseXml属性.来自MSDN:

表示已解析的响应实体主体.

如果响应实体主体不是有效的XML,则此属性返回已解析的DOMDocument,以便您可以访问该错误.此属性不返回IXMLDOMParseError本身,但可以从DOMDocument访问它.

在我的例子中,responseXml属性存在,因为它应该:

Assert(http.responseXml <> nil);
Run Code Online (Sandbox Code Playgroud)

并且没有responseText的解析错误:

doc := http.responseXml as DOMDocument60;
Assert(doc.parseError.errorCode = 0);
Run Code Online (Sandbox Code Playgroud)

应该有,因为xml是有效的.

除了当我查看http.responseXml文档对象时,它是空的:

   Memo1.Lines.Add('============responseXml');
   Memo1.Lines.Add(doc.xml);
Run Code Online (Sandbox Code Playgroud)

是时IXMLHttpRequest(和IXMLServerHttpRequest)返回一个空的XML文档,时间为:

  • 有xml
  • xml有效
  • 没有解析错误

长形式:

uses
    msxml2_tlb;

procedure TForm1.Button1Click(Sender: TObject);
var
    szUrl: string;
    http: IXMLHTTPRequest;
    doc: DOMDocument60;
begin
    szUrl := 'http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml';

    http := CoXMLHTTP60.Create; //or CoServerXmlHttpRequest.Create
    http.open('GET', szUrl, False, '', '');
    http.send(EmptyParam);

    Assert(http.Status = 200);

    doc := http.responseXml as DOMDocument60;
    Assert(doc.parseError.errorCode = 0);

    ShowMessage('"'+doc.xml+'"');
end;
Run Code Online (Sandbox Code Playgroud)

我如何XmlHttpRequest(更重要的是ServerXMLHTTP60)表现得像记录的那样?

Ian*_*oyd 4

发现问题了

我使用Fiddler将 http 响应保存到文本文件。之后,我可以修改响应文件,并指示 fiddler 提供我手工制作的替代方案,而不是访问原始网站。

在此输入图像描述

经过 3 个小时的摆弄,我成功地找到了原始 http 响应头中的问题:

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3
Run Code Online (Sandbox Code Playgroud)

应该

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/xml; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3
Run Code Online (Sandbox Code Playgroud)

一旦发现问题,我就能够找到解释该行为的文档

MSXML 6.0 支持的 MIME 类型有:

  • 文本/xml
  • 应用程序/xml
  • 或任何以“ +xml ”结尾的内容,例如“ application/rss+xml

我正在获取的 RSS 提要实际上是资源定义格式 (RDF) 提要,其中内容类型应该是:

application/rdf+xml
Run Code Online (Sandbox Code Playgroud)

他们的用途是:

text/html
Run Code Online (Sandbox Code Playgroud)

在很多层面上都是错误的。

所以我所经历的行为是设计使然;尽管令人沮丧 - 因为没有简单的方法可以知道它是否responseXml“有效”。

  • responseXml对象将被分配
  • parseError对象将被分配
  • parseError.ErrorCode
  • responseXml.documentElement 将为 nil