Indy Header Last-Modified - 日期编码的参数无效

问题描述 投票:2回答:1

我正在使用Indy的TIdHTTP。我发出2个不同的请求,一个标题包含'Last-Modified'标记,另一个标题不包含。带标记的标题会引发异常:

'Invalid Argument to date encode'

我已经遇到this问题,Remy Lebeau说,TIdHttp现在能够解析ISO8601日期,但它似乎对我不起作用。正如您在下面看到的,除了更改UserAgent之外,我没有对组件进行任何操作。我错过了什么吗?

url :=  'https://api.priceapi.com/v2/jobs/' + JobID+ '?token=' + Token;
http := TIdHTTP.Create(nil);
http.Request.UserAgent := 'XXXXX'; //Some UserAgent
try
  ssl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    http.IOHandler := ssl;
    try
      jo := TJsonObject.ParseJSONValue(http.get(url)) as TJSONObject;
      result := jo.GetValue('status').Value;
    finally
    end;
  finally
    ssl.Free;
  end;
finally
  http.Free;
end;

最后修改的标头:

Cache-Control: no-cache
Content-Disposition: attachment; 
filename="20181025145103_google_shopping_de_5bd1d857bbd7e520c12841d7.json"
Content-Transfer-Encoding: binary
Content-Type: application/json
Last-Modified: 2018-10-25 14:51:23 +0000
Vary: Origin
X-Accel-Buffering: no
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: b05aa8fe-7ea9-4152-8470-a75f9816549f
X-Runtime: 0.099212
X-XSS-Protection: 1; mode=block
transfer-encoding: chunked
Connection: keep-alive

没有Last-Modified的标头:

Cache-Control: max-age=0, private, must-revalidate', nil
Content-Type: application/json; charset=utf-8', nil
ETag: W/"43c4a8865a5ebe565f3920779a962e93"', nil
Vary: Origin', nil
X-Content-Type-Options: nosniff', nil
X-Frame-Options: SAMEORIGIN', nil
X-Request-Id: 344ac82e-0d14-4838-ae7e-627c79b78edc', nil
X-Runtime: 0.062357', nil
X-XSS-Protection: 1; mode=block', nil
Content-Length: 157', nil
Connection: Close', nil

堆栈跟踪:

:744717d2 KERNELBASE.RaiseException + 0x62
HIWBase.System.SysUtils.ConvertError($3B68860)
HIWBase.System.SysUtils.EncodeDate(???,???,???)
HIWBase.IdGlobalProtocols.RawStrInternetToDateTime('07:53:37 +0000',0)
HIWBase.IdGlobalProtocols.GMTToLocalDateTime('07:53:37 +0000')
HIWBase.IdHTTPHeaderInfo.TIdEntityHeaderInfo.ProcessHeaders
HIWBase.IdHTTPHeaderInfo.TIdResponseHeaderInfo.ProcessHeaders
HIWBase.IdHTTP.TIdHTTPProtocol.RetrieveHeaders(255)
HIWBase.IdHTTP.TIdCustomHTTP.DoRequest('GET','My URL',nil,$ADF09E0,(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL',$ADF09E0,(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL',(...))
HIWBase.IdHTTP.TIdCustomHTTP.Get('My URL')

我在Indy版本10.6.2.5311

delphi indy
1个回答
1
投票

Last-Modified标题在RFC 2616 Section 14.29 1中定义为:

Last-Modified  = "Last-Modified" ":" HTTP-date

1:RFC 7232 Section 2.2中出现了等效定义。

HTTP-dateRFC 2616 Section 3.3 2中被定义为:

HTTP-date    = rfc1123-date | rfc850-date | asctime-date
rfc1123-date = wkday "," SP date1 SP time SP "GMT"
rfc850-date  = weekday "," SP date2 SP time SP "GMT"
asctime-date = wkday SP date3 SP time SP 4DIGIT
date1        = 2DIGIT SP month SP 4DIGIT
               ; day month year (e.g., 02 Jun 1982)
date2        = 2DIGIT "-" month "-" 2DIGIT
               ; day-month-year (e.g., 02-Jun-82)
date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))
               ; month day (e.g., Jun  2)
time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
               ; 00:00:00 - 23:59:59
wkday        = "Mon" | "Tue" | "Wed"
             | "Thu" | "Fri" | "Sat" | "Sun"
weekday      = "Monday" | "Tuesday" | "Wednesday"
             | "Thursday" | "Friday" | "Saturday" | "Sunday"
month        = "Jan" | "Feb" | "Mar" | "Apr"
             | "May" | "Jun" | "Jul" | "Aug"
             | "Sep" | "Oct" | "Nov" | "Dec"

2:等效定义出现在RFC 7231 Section 7.1.1.1中。

您显示的Last-Modified值与HTTP允许的任何格式都不匹配。

TIdHTTP使用Indy的GMTToLocalDateTime()函数来解析Last-Modified(以及DateExpires)标题。该功能由HTTP,IMAP,NNTP和电子邮件组件共享,因此它支持的日期/时间格式更灵活一些。例如,它确实解析了ISO 8601,您声称Last-Modified值为。但是,您显示的值实际上也不符合ISO 8601。如果有,它看起来会更像这样:

Last-Modified: 2018-10-26T08:37:01+00:00

更糟糕的是,根据你提供的堆栈跟踪,GMTToLocalDateTime()被调用而没有任何日期部分:

HIWBase.IdGlobalProtocols.GMTToLocalDateTime('07:53:37 +0000')

TIdHTTP中可能发生的唯一方法是,如果HTTP服务器发送具有该确切值的Last-Modified(或DateExpires)标头,这也不符合HTTP或ISO 8601标准,并且不按原样处理GMTToLocalDateTime()

简而言之,您正在查询的API发送的是非法的日期/时间格式,TIdHTTP不支持解析(具有讽刺意味的是,因为主要的https://www.priceapi.com网站确实发送了格式正确的HTTP日期/时间字符串)。您应该联系网站管理员并报告他们的API服务器在这方面违反了HTTP协议标准。

话虽这么说,GMTToLocalDateTime()遇到格式错误的日期/时间字符串时,不会引发'Invalid Argument to date encode'异常。它返回TDateTime0.0而不是。您可以看到该异常的唯一方法是在调试器中运行代码。当GMTToLocalDateTime()被赋予格式错误的日期/时间字符串时,它可能会提取它认为有效的数字组件,但在尝试用它们编码最终的TDateTime时会失败。您看到的例外来自RTL的EncodeDate()函数,当它被指定为无效的月/日/年作为输入时。但是GMTToLocalDateTime()在内部捕获了这个例外。您的代码永远不会在运行时看到它,只有调试器才能看到它。

© www.soinside.com 2019 - 2024. All rights reserved.