Delphi RIO中TIdHTTP发送GET请求遇403错误,Postman可正常访问
Delphi RIO中TIdHTTP发送GET请求返回403 Forbidden,但Postman可正常访问的排查
问题描述
在Delphi RIO环境下使用TIdHTTP组件发送GET请求时,收到HTTP 403 Forbidden错误,但相同URL在Postman中能正常访问。该函数在其他场景可正常工作,调整多种TIdHTTP配置后问题仍存在,需排查原因。
函数实现
function HTTPRestApiGet(var HTTP: TIdHTTP; necesitaSSL: Boolean; var SSL: TIdSSLIOHandlerSocketOpenSSL; Usuario, Clave, URLBase, Recurso, CamposSolicitados: string; TiempoEspera: Integer = 5000; LogActivado: Boolean = True): THTTPRestApiResponse; var requerimiento, respuesta: string; LogFile : TIdLogFile; begin LogFile := TIdLogFile.Create(nil); // HTTP.HandleRedirects := True; HTTP.RedirectMaximum := 10; HTTP.ReadTimeout := TiempoEspera; HTTP.MaxAuthRetries := 0; HTTP.HTTPOptions := [hoInProcessAuth]; HTTP.Request.BasicAuthentication := True; HTTP.Request.Username := Usuario; HTTP.Request.Password := Clave; HTTP.Request.Accept := 'http'; HTTP.Request.ContentType := 'application/json'; // HTTP.IOHandler := nil; if necesitaSSL then begin HTTP.IOHandler := SSL; SSL.SSLOptions.Mode := sslmClient; SSL.SSLOptions.Method := sslvSSLv23; end; // Configurar logging LogFile.Filename := 'http_log.txt'; LogFile.Active := True; HTTP.Intercept := LogFile; // try requerimiento := URLBase + IfThen(Recurso <> EmptyStr, '/' + Recurso + IfThen(CamposSolicitados <> EmptyStr, '?_fields=' + CamposSolicitados, ''), EmptyStr); try respuesta := HTTP.Get(requerimiento); except end; finally HTTPRestApiLogRespuesta('GET', requerimiento, respuesta, HTTP.URL.uri, HTTP.ResponseText, HTTP.ResponseCode, LogActivado); with Result do begin requerimiento_exitoso := (HTTP.ResponseCode >= 200) and (HTTP.ResponseCode < 300); respuesta_codigo := HTTP.ResponseCode; respuesta_codigotexto := HTTP.ResponseText; respuesta_texto := respuesta; respuesta_id := -1; end; // LogFile.Free; end; end;
调用代码
HTTP := TIdHTTP.Create(nil); SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil); respuesta := HTTPRestApiGet(HTTP, True, SSL, 'brgroup', '1234', 'https://apis.datos.gob.ar/series/api/series/?ids=148.3_INIVELNAL_DICI_M_26&start_date=' + fecha_desde + '&end_date=' + fecha_hasta, EmptyStr, EmptyStr, 5000, False); SSL.Free; HTTP.Free;
日志返回信息
HTTP/1.1 403 Forbidden
Stat Connected. Sent 03/08/2024 14:31:22: GET /series/api/series/?ids=148.3_INIVELNAL_DICI_M_26&start_date=2024-04-01&end_date=2024-07-01 HTTP/1.1<EOL>Content-Type: application/json<EOL>Host: apis.datos.gob.ar<EOL>Accept: http<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL>Authorization: Basic Og==<EOL><EOL> Recv 03/08/2024 14:31:22: HTTP/1.1 403 Forbidden<EOL>Date: Sat, 03 Aug 2024 17:31:18 GMT<EOL>Content-Type: text/plain; charset=UTF-8<EOL>Content-Length: 16<EOL>Connection: keep-alive<EOL>X-Frame-Options: SAMEORIGIN<EOL>Referrer-Policy: same-origin<EOL>Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0<EOL>Expires: Thu, 01 Jan 1970 00:00:01 GMT<EOL>Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=R4%2FV8fU73LVHwpLIjJ6e%2Bq91jVM76aHSX9KolkAQ2jd6gUdAGWjUl5yOZd728jdQb%2BoIx%2BzuQyFnqhINrrA76CWjQv%2Fw17ciaSSFRAmKOMSEBszwUe3s6K0en7dhPVXEC3wH5A%3D%3D"}],"group":"cf-nel","max_age":604800}<EOL>NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}<EOL>Server: cloudflare<EOL>CF-RAY: 8ad80a629ecaa78f-EZE<EOL>alt-svc: h3=":443"; ma=86400<EOL><EOL>error code: 1010
Postman正常请求的curl命令
curl --location 'https://apis.datos.gob.ar/series/api/series/?ids=148.3_INIVELNAL_DICI_M_26&start_date=2024-04-01&end_date=2024-07-01' \ --header 'Accept: http' \ --header 'Content-Type: application/json' \ --header 'Authorization: Basic Og=='
排查分析与解决方案
核心问题定位
从日志可见请求被Cloudflare拦截(Server: cloudflare、error code: 1010),结合Postman与TIdHTTP的请求差异,主要问题点如下:
- User-Agent标识问题:TIdHTTP默认的
User-Agent属于老旧且明确标识为程序库的请求头,Cloudflare反爬机制易将其判定为非合法请求。 - Authorization头异常:日志中认证头解码后为空,说明TIdHTTP自动生成Basic认证头的逻辑未正常工作,可能是
MaxAuthRetries := 0与hoInProcessAuth的组合导致认证流程未触发。 - SSL/TLS协议版本兼容:当前设置的
sslvSSLv23协议范围较广,Cloudflare可能强制要求TLS 1.2及以上版本,旧协议易被拦截。
针对性解决方案
1. 修改User-Agent为浏览器或Postman标识
在函数中添加或修改User-Agent设置:
HTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36'; // 或使用Postman的User-Agent // HTTP.Request.UserAgent := 'PostmanRuntime/7.39.0';
2. 手动构造Authorization认证头
关闭TIdHTTP自动Basic认证,手动生成认证头避免逻辑异常:
HTTP.Request.BasicAuthentication := False; HTTP.Request.CustomHeaders.Add('Authorization: Basic ' + TIdEncoderMIME.EncodeString(Usuario + ':' + Clave));
3. 指定SSL/TLS协议版本为TLS 1.2或更高
将SSL协议方法修改为TLS 1.2:
SSL.SSLOptions.Method := sslvTLSv1_2; // 若环境支持,可尝试TLS 1.3 // SSL.SSLOptions.Method := sslvTLSv1_3;
4. 修正Accept请求头(可选)
虽然Postman也传了Accept: http,但该值不符合标准MIME类型规范,可修改为更通用的格式:
HTTP.Request.Accept := 'application/json, */*';
验证步骤
优先修改User-Agent并测试,若问题解决则说明是反爬拦截;若仍存在问题,再依次验证Authorization头和SSL协议版本的调整。
内容的提问来源于stack exchange,提问作者Speaker
相关产品推荐
相关产品推荐

