一千萬個為什麽

搜索

HttpSendRequest沒有從服務器獲取最新文件

我的應用程序中的HTTP請求存在問題,因此如果遠程文件與本地文件的大小相同(即使其修改時間不同,因為其內容已更改),嘗試下載它會快速返回並且不下載較新的文件。

簡而言之,我遵循的過程是:使用 INTERNET_FLAG_RESYNCHRONIZE 標誌設置HTTP連接並調用HttpSendRequest();然後檢查HTTP狀態代碼並將其發現為“200”。

  • If the remote file is updated, but remains the same size as the local copy: The local file is unchanged after running the app. If I call HttpQueryInfo() with HTTP_QUERY_LAST_MODIFIED after sending the request, it gives me the actual last modified time of the server's file, which I can see is different from the local file I am trying to have it overwrite.
  • If the remote file is updated, and the file size becomes different from the local copy: It is downloaded and overwrites the local copy as expected.

這是一個相當簡略的代碼版本,用於刪除幫助程序和錯誤檢查:

// szAppName = our app name
HINTERNET hInternetHandle = InternetOpen( szAppName,
    INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
// szServerName = our server name
hInternetHandle = InternetConnect( hInternetHandle, szServerName,
    INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, 0 );

// szPath = the file to download
LPCSTR aszDefault[2] = { "*/*", NULL };
DWORD dwFlags = 0
| INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP
| INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS
| INTERNET_FLAG_KEEP_CONNECTION
| INTERNET_FLAG_NO_AUTH
| INTERNET_FLAG_NO_AUTO_REDIRECT
| INTERNET_FLAG_NO_COOKIES
| INTERNET_FLAG_NO_UI
| INTERNET_FLAG_RESYNCHRONIZE;
HINTERNET hHandle = HttpOpenRequest( hInternetHandle, "GET", szPath, NULL,
    NULL, aszDefault, dwFlags, 0 );

DWORD dwTimeOut = 10 * 1000;//In milliseconds
InternetSetOption( hInternetHandle, INTERNET_OPTION_CONNECT_TIMEOUT,
    &dwTimeOut, sizeof( dwTimeOut ) );
InternetSetOption( hInternetHandle, INTERNET_OPTION_RECEIVE_TIMEOUT,
    &dwTimeOut, sizeof( dwTimeOut ) );
InternetSetOption( hInternetHandle, INTERNET_OPTION_SEND_TIMEOUT,
    &dwTimeOut, sizeof( dwTimeOut ) );
DWORD dwRetries = 5;
InternetSetOption( hInternetHandle, INTERNET_OPTION_CONNECT_RETRIES,
    &dwRetries, sizeof( dwRetries ) );

HttpSendRequest( hInternetHandle, NULL, 0, NULL, 0 );

因為我發現我可以查詢遠程文件的最後修改時間,並且發現它是準確的,我知道它實際上是到達服務器的。我認為指定 INTERNET_FLAG_RESYNCHRONIZE 會強制文件 resynch如果它已經過時了。我錯了嗎?這是它應該如何工作嗎?


編輯:我已經使用數據包嗅探器進行了一些調查,這裏有一些額外的信息:

如果遠程和本地文件完全相同,則這是交換:

GET /test.bmp HTTP/1.1
Accept: */*
If-None-Match: "1c1467112ee6ca1:369"
User-Agent: Internal Testing
Host: ****************
Connection: Keep-Alive

HTTP/1.1 304 Not Modified
Last-Modified: Tue, 27 Apr 2010 17:21:26 GMT
Accept-Ranges: bytes
ETag: "1c1467112ee6ca1:369"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Tue, 27 Apr 2010 18:10:26 GMT

現在,如果遠程文件已更改,但文件大小保持不變:

GET /test.bmp HTTP/1.1
Accept: */*
If-None-Match: "1c1467112ee6ca1:369"
User-Agent: Internal Testing
Host: ****************
Connection: Keep-Alive

HTTP/1.1 200 OK
Content-Length: 419958
Content-Type: image/bmp
Last-Modified: Tue, 27 Apr 2010 18:11:17 GMT
Accept-Ranges: bytes
ETag: "b65425835e6ca1:369"
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Tue, 27 Apr 2010 18:11:33 GMT
[Block of data]

因此,服務器確實在文件發生變化時發送文件,但我的應用程序似乎仍然認為它沒有更改。我認為問題在於我的應用程序如何處理響應;這不是我自己的代碼,編寫它的人很久以前就已經開始了。

我發現的一個問題是,在上述場景的兩個中,當我用 HTTP_QUERY_STATUS_CODE 調用 HttpQueryInfo()時,我得到了200。但是,在上面的第一種情況下,我可以看到實際的服務器響應是304,而不是200.挖掘我們正在使用的代碼,我發現它似乎試圖通過進行文件大小比較來解決這個問題,並假設如果文件大小相同,則文件沒有改變;因此,我遇到的問題!

所以現在我的問題更簡單:為什麽 HttpQueryInfo()即使在服務器返回3XX錯誤之一時也會返回200?我發現有些人在網上問了類似的問題,但他們要麽沒有收到回復或正在直接處理Web瀏覽器。

最佳答案

I believe that INTERNET_FLAG_RESYNCHRONIZE uses the If-Modified-Since HTTP request header field and checks the status code while HTTP_QUERY_LAST_MODIFIED will (I think) just does a HEAD request & checks the HTTP response Last-Modified header field.

Try a HTTP_QUERY_IF_UNMODIFIED_SINCE & a HTTP_QUERY_LAST_MODIFIED with HttpQueryInfo() and compare the results [as a side note if you have a HTTP sniffer up & running it may clear some things up for all of us...].

As a quick & dirty solution you can use the INTERNET_FLAG_RELOAD instead of INTERNET_FLAG_RESYNCHRONIZE to force the file reload each & every time you request it.

HTH

轉載註明原文: HttpSendRequest沒有從服務器獲取最新文件