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.
2 回答
您可以使用 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
请求并存储LastModified
和ContentLength
变量。然后定期发出HEAD
请求以测试更改(TTimer
例如通过)。
这些 Header 参数取决于 Web 服务器实现,并且可能不会返回服务器上的文件系统日期时间(例如动态页面)。您的服务器可能根本不会返回这些参数。
例如,对于HTML
IIS 上的静态页面,Last-Modified
返回文件系统上次修改的日期时间,这是您想要的。
对于动态内容(例如 php、asp、.NET 等),如果您控制网络服务器,您不妨HTTP
在服务器端添加自己的自定义响应标头以指示文件系统日期时间(例如X-Last-Modified
)或根据您的需要设置响应Last-Modified
标头并在客户端检查此标头。
如果您需要检查/散列整个 HTTP 内容,则需要发出一个GET
方法: http.Get(URL)
多亏了 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;