我的应用程序中的HTTP请求存在问题,因此如果远程文件与本地文件大小相同(即使其修改时间不同,因为其内容已更改),尝试下载它会快速返回,并且不会下载较新的文件。
简而言之,我所遵循的流程是:使用INTERNET_FLAG_RESYNCHRONIZE
标志设置HTTP连接并调用HttpSendRequest();然后检查HTTP状态代码并将其发现为“200”。
HttpQueryInfo()
调用HTTP_QUERY_LAST_MODIFIED
,它会告诉我服务器文件的实际上次修改时间,我可以看到它与我试图覆盖它的本地文件不同。 这是一个相当简略的代码版本,用于删除帮助程序和错误检查:
// 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 if it's out of date。我错了吗?这只是它应该如何工作吗?
编辑:我已经使用数据包嗅探器进行了一些调查,这里还有一些其他信息:
如果远程和本地文件完全相同,那就是交换:
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]
因此,服务器确实在文件发生变化时发送,但我的应用程序似乎仍然认为它没有更改。我认为问题在于我的应用程序如何处理响应;这不是我自己的代码,编写它的人很久以前就已经开始了。
我发现的一个问题是,在上述场景的两个中,当我用HttpQueryInfo()
调用HTTP_QUERY_STATUS_CODE
时,我得到200回。但是,在上面的第一种情况下,我可以看到实际的服务器响应是304,而不是200.挖掘我们正在使用的代码,我发现它似乎试图通过进行文件大小比较来解决这个问题,并假设如果文件大小相同,则文件没有改变;因此,我遇到了问题!
所以现在我的问题更简单:即使服务器返回其中一个3XX错误,为什么HttpQueryInfo()
会返回200?我发现有些人在网上问了类似的问题,但他们要么received no responses要么直接与网络浏览器打交道。
答案 0 :(得分:1)
我相信INTERNET_FLAG_RESYNCHRONIZE
使用If-Modified-Since
HTTP请求标头字段并检查状态代码,而HTTP_QUERY_LAST_MODIFIED将(我认为)只执行HEAD请求&检查HTTP响应Last-Modified
标头字段。
尝试HTTP_QUERY_IF_UNMODIFIED_SINCE
&一个HTTP_QUERY_LAST_MODIFIED
与HttpQueryInfo()
并比较结果[如果你有一个HTTP嗅探器,则作为附注说明&运行它可能会为我们所有人清除一些事情......]。
快速&脏解决方案,您可以使用INTERNET_FLAG_RELOAD
代替INTERNET_FLAG_RESYNCHRONIZE
强制文件重新加载每个&每次你提出要求。
HTH
答案 1 :(得分:1)
根据MSDN INTERNET_FLAG_RESYNCHRONIZE
,如果资源自上次下载以来已被修改,则“重新加载HTTP资源”。请参阅http://msdn.microsoft.com/en-us/library/aa383661(v=vs.85).aspx。
HttpQueryInfo()
返回的200确实很奇怪 - 它应该返回真实的状态代码。
如果可以,请更改代码以进行校验和比较,而不是文件大小比较。
如果没有,你可以看看更多的东西:
http://yourserver/image.jpg?r=5452435234
INTERNET_FLAG_NO_CACHE_WRITE
和INTERNET_FLAG_PRAGMA_NOCACHE
如{b}中所述的HttpOpenRequest()
和InternetOpenUrl()
http://msdn.microsoft.com/en-us/library/aa383661(VS.85).aspx#INTERNET_FLAG_NO_CACHE_WRITE。