6

I want to display a 'news' page in a form using Deplhi TWebBrowser. The news page is a simple HTML page which we upload to our website from time to time and may be output from various tools. The display is fine but I'd like to know in my app whether it has changed since I last displayed it, so ideally I'd like to get either its modified date/time or its size / checksum. Precision is not important and ideally should not rely on properties that might fail because 'simple' tools were used to edit the HTML file such as NotePad. Checking on the web there are several document modified java calls but I really dont know where to start with those. I've looked through the numerous calls in Delphi's Winapi.WinInet unit and I see I can fetch the file with HTTP to examine it but that seems like cracking a walnut with a sledgehammer. I also cannot see any file date time functionality which makes me think I'm missing something obvious. I'm using Delphi XE5. In which direction should I be looking please? Thanks for any pointers.

4

2 回答 2

4

您可以使用 IndyTIdHTTP发送HEAD请求并检查Last-Modified/Content-Length标头。

例如:

procedure TForm1.Button1Click(Sender: TObject);
var
  Url: string;
  Http: TIdHTTP;
  LastModified: TDateTime;
  ContentLength: Integer;  
begin
  Url := 'http://yoursite.com/newspage.html';
  Http := TIdHTTP.Create(nil);
  try
    Http.Head(Url);
    LastModified := Http.Response.LastModified;
    ContentLength := Http.Response.ContentLength;
    ShowMessage(Format('Last-Modified: %s ; Content-Length: %d', [DateTimeToStr(LastModified), ContentLength]));
  finally
    Http.Free;
  end;
end;

TWebBrowser.DocumentComplete事件被触发时,发出HEAD请求并存储LastModifiedContentLength变量。然后定期发出HEAD请求以测试更改(TTimer例如通过)。

这些 Header 参数取决于 Web 服务器实现,并且可能不会返回服务器上的文件系统日期时间(例如动态页面)。您的服务器可能根本不会返回这些参数。

例如,对于HTMLIIS 上的静态页面,Last-Modified返回文件系统上次修改的日期时间,这是您想要的。

对于动态内容(例如 php、asp、.NET 等),如果您控制网络服务器,您不妨HTTP在服务器端添加自己的自定义响应标头以指示文件系统日期时间(例如X-Last-Modified)或根据您的需要设置响应Last-Modified标头并在客户端检查此标头。


如果您需要检查/散列整个 HTTP 内容,则需要发出一个GET方法: http.Get(URL)

于 2014-08-11T11:03:37.127 回答
1

多亏了 kobik、David 和 TLama 的各种建议和指示,我意识到我确实需要一把大锤,我终于想出了这个解决方案(我可能不是第一个,也不是最后一个!)。我不得不阅读文件内容,因为这似乎是检测更改的更好方法。下面的代码很少从 TTimer 调用“CheckForWebNewsOnTimer”,并使用 Indy 读取新闻页面,对其内容进行 MD5 散列,并将其与存储在注册表中的先前散列进行比较。如果内容发生变化,或经过 120 天,页面会弹出。代码有皱纹,例如页面上链接图像的更改可能不会触发更改,但是嘿,它唯一的新闻和文本几乎总是会更改。

function StreamToMD5HashHex( AStream : TStream ) : string;
// Creates an MD5 hash hex of this stream
var
  idmd5 : TIdHashMessageDigest5;
begin
  idmd5 := TIdHashMessageDigest5.Create;
  try
    result := idmd5.HashStreamAsHex( AStream );
  finally
    idmd5.Free;
  end;
end;



function HTTPToMD5HashHex( const AURL : string ) : string;
var
  HTTP : TidHTTP;
  ST : TMemoryStream;
begin
  HTTP := TidHTTP.Create( nil );
  try
    ST := TMemoryStream.Create;
    try
      HTTP.Get( AURL, ST );
      Result := StreamToMD5HashHex( ST );
    finally
      ST.Free;
    end;
  finally
    HTTP.Free;
  end;
end;




function ShouldShowNews( const ANewHash : string; AShowAfterDays : integer ) : boolean;
const
  Section = 'NewsPrompt';
  IDHash  = 'LastHash';
  IDLastDayNum = 'LastDayNum';
var
  sLastHash : string;
  iLastPromptDay : integer;
begin


  // Check hash
  sLastHash := ReadRegKeyUserStr( Section, IDHash, '' );
  Result := not SameText( sLastHash, ANewHash );
  if not Result then
    begin
    // Check elapsed days
    iLastPromptDay := ReadRegKeyUserInt( Section, IDLastDayNum, 0 );
    Result := Round( Now ) - iLastPromptDay > AShowAfterDays;
    end;

  if Result then
    begin
    // Save params for checking next time.
    WriteRegKeyUserStr( Section, IDHash, ANewHash );
    WriteRegKeyUserInt( Section, IDLastDayNum, Round(Now) );
    end;
end;





procedure CheckForWebNewsOnTimer;
var
  sHashHex, S : string;
begin
  try
    S := GetNewsURL; // < my news address
    sHashHex := HTTPToMD5HashHex( S );
    If ShouldShowNews( sHashHex, 120 {days default} ) then
      begin
      WebBrowserDlg( S );
      end;

  except
    // .. ignore or save as info
  end;
end;
于 2014-08-12T08:23:16.080 回答