You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Indy TIdHTTP无法获取自定义404响应体的解决方法咨询

如何通过TIdHTTP获取自定义404响应体?

我的HTTP服务器在REST路由不存在时,会返回如下自定义JSON格式的404错误文本:

{"sessionIdent":"051F-dUen7-tetW-kNf82-WxT","Details":[{"messageCode":60,"messageCategory":"","messageText":"No matching route for \"POST \/Warehouse\/A1\/Orders\/execute\""}]}

使用JavaScript的XMLHttpRequest可以正常获取该响应文本:

function httpReq(method, url, headers, jsonStr, userName, password) {
    try
    {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open(method, url, true);

        xmlhttp.onreadystatechange = function () {
            console.log("onreadystatechange");
            if (xmlhttp.readyState == 4) {
                console.log("ready");
                console.log(xmlhttp.status);
                console.log(xmlhttp.responseText);
            }
        }
        // Send the request
        xmlhttp.setRequestHeader('Cache-Control', 'no-cache, max-age=0');
        xmlhttp.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
        xmlhttp.setRequestHeader('Session-Ident', '051F-dUen7-tetW-kNf82-WxT');
        xmlhttp.setRequestHeader('Accept', 'application/json');
        if (headers) {
            var headerKeys = Object.keys(headers);
            Object.keys(headers).forEach(key => {
                xmlhttp.setRequestHeader(key, headers[key]);
            });
        }
        if ((userName !== "") && (password !== ""))
        {
          xmlhttp.setRequestHeader("Authorization", "Basic " + btoa(userName + ":" + password));
        }
        console.log("before send");
        xmlhttp.send(jsonStr);
        console.log("after send");
    }
    catch (ex)
    {
        console.log(ex);
    }
}

但使用Indy的TIdHTTP组件时,默认会抛出EIdHTTPProtocolException异常(消息为"HTTP/1.1 404 Not Found"),无法获取响应文本。开启hoNoProtocolErrorException选项后:

_client.HTTPOptions := _client.HTTPOptions + [hoNoProtocolErrorException];

虽然不再抛出异常,但获取到的响应文本为空,当前使用的Pascal代码如下:

procedure TFormRestTest._httpSend(AMethod, APath, AHeaders, ABody: string);
var
  queryData, replyData: TStream;
  resultText: string;
begin
  queryData := TStringStream.Create(ABody, TEncoding.UTF8);
  try
    replyData := TMemoryStream.Create;
    try
      _client.Request.ContentType := 'application/json';
      _client.Request.CharSet := 'UTF-8';
      _client.Request.BasicAuthentication := True;
      _client.Request.Username := 'Username';
      _client.Request.Password := 'Password';
      _client.Request.CustomHeaders.Clear;
      _client.Request.CustomHeaders.Text := AHeaders;
      _client.DoRequest(AMethod, APath, queryData, replyData, []);
      replyData.Position := 0;
      resultText = ReadStringAsCharset(replyData, _client.Response.CharSet)]);
      _log(resultText);  //resultText is empty
    finally
      replyData.Free();
    end;
  finally
    queryData.Free();
  end;
end;

解决方法

要获取自定义404的响应体,需要做以下两处修改:

  1. 给DoRequest添加hoWantProtocolErrorContent标志
    即使开启了hoNoProtocolErrorException,TIdHTTP的DoRequest默认不会读取错误状态码(如404)对应的响应体,必须显式传入hoWantProtocolErrorContent选项,才会将错误响应的内容写入到replyData流中。

  2. 修正代码中的语法错误

    • 将赋值语句resultText = ...改为Pascal正确的赋值符:=
    • 移除ReadStringAsCharset调用末尾多余的]

另外,确保请求的Accept头设置为application/json,保证服务器返回JSON格式的响应(可通过AHeaders传入,或单独调用_client.Request.Accept := 'application/json')。

修改后的完整代码如下:

procedure TFormRestTest._httpSend(AMethod, APath, AHeaders, ABody: string);
var
  queryData, replyData: TStream;
  resultText: string;
begin
  queryData := TStringStream.Create(ABody, TEncoding.UTF8);
  try
    replyData := TMemoryStream.Create;
    try
      _client.Request.ContentType := 'application/json';
      _client.Request.CharSet := 'UTF-8';
      _client.Request.Accept := 'application/json'; // 确保Accept头正确
      _client.Request.BasicAuthentication := True;
      _client.Request.Username := 'Username';
      _client.Request.Password := 'Password';
      _client.Request.CustomHeaders.Clear;
      _client.Request.CustomHeaders.Text := AHeaders;
      // 添加hoWantProtocolErrorContent选项
      _client.DoRequest(AMethod, APath, queryData, replyData, [hoWantProtocolErrorContent]);
      replyData.Position := 0;
      // 修正语法错误
      resultText := ReadStringAsCharset(replyData, _client.Response.CharSet);
      _log(resultText);
    finally
      replyData.Free();
    end;
  finally
    queryData.Free();
  end;
end;

内容的提问来源于stack exchange,提问作者Paul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:00:59