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的响应体,需要做以下两处修改:
给
DoRequest添加hoWantProtocolErrorContent标志
即使开启了hoNoProtocolErrorException,TIdHTTP的DoRequest默认不会读取错误状态码(如404)对应的响应体,必须显式传入hoWantProtocolErrorContent选项,才会将错误响应的内容写入到replyData流中。修正代码中的语法错误
- 将赋值语句
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
相关产品推荐
相关产品推荐

