【问题标题】:Why does this web server return code 404 for Indy, but code 200 for every browser?为什么此 Web 服务器为 Indy 返回代码 404,但为每个浏览器返回代码 200?
【发布时间】:2013-04-06 00:52:02
【问题描述】:

我有一个在所有浏览器中都可以正常工作的 URL(在 2 台计算机上测试了 5 个),但是如果我尝试使用 Indy Http 客户端的 Get() 获取页面内容,它会返回错误代码 404,找不到页面.这是最新的 Indy SVN 版本 (4985)。

为什么这个网络服务器为 Indy 返回代码 404,而为每个浏览器返回代码 200?

我怀疑这可能是 Indy 中的错误,因为 URL 中的“#”字符(Indy 将 # 之后的所有内容都切断了)。如果是这样,有什么办法可以解决这个问题。也许用转义码替换 # 字符?

这是我的示例代码。所需要的只是带有 Indy 组件的 Delphi 以及带有按钮和备忘录的表单。

procedure TForm1.Button1Click(Sender: TObject);
var HTTPCLIENT1: TIdHTTP;
begin
  try
   try
     HTTPCLIENT1 := TIdHTTP.Create(nil);
     Memo1.Clear;
     with HTTPCLIENT1 do
     begin
          HandleRedirects := True;
          Request.UserAgent   := 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31';
          Memo1.Text := Get('http://www.visionofhumanity.org/gpi-data/#/2011/scor/');
          Caption := ResponseText;
     end;
   except
     On e: Exception do
     begin
          Memo1.Lines.Add('Exception: '+e.Message);
     end;
   end;
  finally
     HTTPCLIENT1.Free;
  end;
end;

【问题讨论】:

  • 根据the answer to your previous question,修订版 4985 应该可以解决该问题。你确定你已经正确安装了吗?您是否使用过 WireShark 比较浏览器发送的内容与您的程序发送的内容?
  • 我同意 Rob 的观点。我修复了那个错误,所以# 和它之后的所有东西都不会再发送到服务器了。我会再次检查,但上次肯定工作正常。
  • @RobKennedy 这是另一个问题。另一篇文章是关于在 URL 中使用锚点获取错误代码 500。这是固定的。这个问题是关于在 URL 中获取没有锚点的代码 404。
  • @Casady:就像 Rob 所说,您应该使用 Wireshark 或其他数据包嗅探器来诊断此类问题。您之前的问题是由于 Indy 发送的 URL 与浏览器发送的 URL 不同,导致一系列重定向最终在服务器端失败。这个问题很可能类似。因此,您需要确保 Indy 实际上发送的 URL 与浏览器发送的 URL 相同。
  • @RemyLebeau 你是对的。这个问题类似但不一样,出于某种原因,Indy 不会从 URL 中删除锚点,即使在 build 4985 中也是如此。

标签: delphi indy


【解决方案1】:

# 是 URL 中的保留字符。如果要在 URL 中使用保留字符,则需要对它们进行 url 编码。 TIdHTTP 不会为您这样做。它要求您传递 编码 URL,但您传递的是 未编码 URL。由于# 未编码,因此它被视为锚点并被剥离,因此您实际上是在请求http://www.visionofhumanity.org/gpi-data/,因此是404 回复。

# 被 url 编码为 %23,所以使用这个:

Memo1.Text := Get('http://www.visionofhumanity.org/gpi-data/%23/2011/scor/');

或者这个:

Memo1.Text := Get(TIdURI.URLEncode('http://www.visionofhumanity.org/gpi-data/#/2011/scor/'));

更新:我找到了问题所在。这是另一个TIdURI 解析错误,这一次与/ 字符后# 字符有关。 TIdURI 在检查 # 字符之前检查 / 字符,因此 URL 的锚部分最终出现在 TIdURI.Path 属性中(以前它最终出现在 TIdURI.Params 属性中),因此提交到服务器。我签入了一个新的修复程序(SVN rev 4987)。

【讨论】:

  • visionofhumanity.org/gpi-data/%23/2011/scor 不适用于 Indy,也不适用于 Web 浏览器。
  • 您不应该给网络浏览器一个编码的 URL,它会在传输过程中对其进行编码。 TIdHTTP 需要预编码的 URL。当我有机会时,我将不得不测试 URL,但如果原始未编码的 url 在浏览器中工作,它应该可以正常工作。他们是等价的。同样,请使用数据包嗅探器进行验证,以确保 TIdHTTP 发送的内容与网络浏览器发送的内容相匹配。
  • 我已经安装了 WireShark,并且 Chrome 会从 # 开始删除所有内容,正如 Indy 应该的那样,但它没有。我假设在 Indy 中仍然存在一个未被 #4985 修复的锚错误
  • @Casady:我找到了这个错误,我会尽快检查修复。
  • @Casady:修复程序现已签入。
【解决方案2】:

你的怀疑是正确的。您已在请求中包含地址的# 部分。浏览器不会这样做,因为该部分是为 页内 导航保留的。服务器不知道这一点,因此它会尝试获取与您提供给它的 full URL 对应的资源,包括 # 和之后的所有内容。没有匹配项,因此失败并显示状态 404。

要么像浏览器那样做,在将请求发送到服务器之前从 URL 中删除该部分,要么将 Indy 更新到修订版 4987,以便它会自动发生。仅仅逃离角色将继续产生状态 404。

【讨论】:

  • SVN 修订版 4985 修复了 TIdURI 中未正确剥离 #...(如果存在)的错误。您无需手动将其剥离。我同意 Rob 的评论,即 4985 可能没有正确安装。
  • @RemyLebeau 4985 已正确安装,因为旧问题已在我的系统上修复。旧问题是一个带有锚点的 URL,它在浏览器中给出 200,但在 Indy 中给出 500。 #4985 修复了这个问题,它给出了 200 indy。但是使用新 URL (visionofhumanity.org/gpi-data/#/2011/scor) 和 Build #4985 Indy 给出 404,但浏览器给出 200。我提出了一个新问题,因为该问题与之前修复的问题不是 100% 相关。
  • @RobKennedy “按照浏览器的做法,在将请求发送到服务器之前从 URL 中删除该部分。仅仅转义字符将继续产生状态 404。”我为什么要剥离任何东西? Indy 自己做! #4985 版本修复了错误剥离锚的问题,但这是一个新问题。
  • 如果去掉锚部分,链接是否有效?似乎是一个基本的测试。另外,我强烈建议您使用 Wire Shark 自己进行一些调试。它可以准确地向您显示您的程序通过网络发送的请求。将其与某些浏览器发送的内容进行比较。当您发现有什么不同时,您可以使用该信息来调查您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-04
  • 1970-01-01
  • 1970-01-01
  • 2017-11-01
  • 2012-12-17
相关资源
最近更新 更多