Функции WinINet имеют простую, но гибкую встроенную поддержку кэширования. Все данные, полученные из сети, кэшируются на жестком диске и извлекаются для последующих запросов. Приложение может управлять кэшированием для каждого запроса. Для HTTP-запросов с сервера большинство полученных заголовков также кэшируются. При выполнении HTTP-запроса из кэша кэша кэшированные заголовки также возвращаются вызывающей объекту. Это упрощает скачивание данных, независимо от того, поступают ли данные из кэша или из сети.
Приложения должны правильно выделить буфер, чтобы получить требуемые результаты при использовании функций постоянного кэширования URL-адресов. Дополнительные сведения см. в разделе Использование буферов.
Поведение кэша во время обработки ответа
Кэш WinINet соответствует директивам управления кэшем HTTP, описанным в RFC 2616. Директивы управления кэшем и флаги набора приложений определяют, что может быть кэшировано; Однако WinINet определяет, что на самом деле кэшируется, на основе следующего критерия:
WinINet кэширует только ответы HTTP и FTP.
Кэш может хранить только правильно выполненные ответы и использовать в ответе на последующий запрос. Ответы с надлежащим поведением определяются как ответы, которые возвращаются успешно.
По умолчанию WinINet кэширует успешные ответы, если только директива управления кэшем с сервера или определенный приложением флаг не указывают на то, что ответ может не кэшироваться.
Как правило, ответы на команду GET кэшируются, если выполняются перечисленные выше требования. Ответы на команды PUT и POST ни при каких обстоятельствах не кэшируются.
Элементы будут кэшироваться даже при заполнении кэша. Если добавленный элемент превышает предельный размер кэша, планируется очистка кэша. По умолчанию элементы не гарантированно будут храниться в кэше более 10 минут. Дополнительные сведения см. в разделе Кэш-мусорщик ниже.
По умолчанию https кэшируется. Это управляется глобальным параметром, который не может быть переопределен директивами кэша, определяемыми приложением. Чтобы переопределить глобальный параметр, выберите апплет Свойства браузера на панели управления и перейдите на вкладку Дополнительно. Установите флажок "Не сохранять зашифрованные страницы на диск" в разделе "Безопасность".
Кэш scavenger
Сборщик кэша периодически очищает элементы из кэша. Если элемент добавляется в кэш и кэш заполнен, он добавляется в кэш и планируется очистка кэша. Если сборщик кэша завершает цикл очистки и кэш не достиг предела кэша, то при добавлении другого элемента в кэш планируется еще один раунд. Как правило, очистка мусора планируется, когда добавленный элемент помещает кэш сверх предельного размера. По умолчанию минимальное время жизни в кэше равно 10 минутам, если иное не указано в директиве управления кэшем. При инициации очистки кэша нет никакой гарантии, что самые старые элементы будут удалены первыми из кэша.
Кэш является общим для всех приложений WinINet на компьютере для одного пользователя. Начиная с Windows Vista и Windows Server 2008, размер кэша устанавливается равным 1/32 размера диска с минимальным размером 8 МБ и максимальным размером 50 МБ.
Использование флагов для управления кэшированием
Флаги кэширования позволяют приложению контролировать, когда и как оно использует кэш. Эти флаги можно использовать отдельно или в сочетании с параметром dwFlags в функциях , которые обращаются к сведениям или ресурсам в Интернете. По умолчанию функции хранят все данные, скачанные из Интернета.
Для управления кэшированием можно использовать следующие флаги.
Не выполняет сетевые запросы. Все сущности возвращаются из кэша. Если запрошенного элемента нет в кэше, возвращается подходящая ошибка, например ERROR_FILE_NOT_FOUND. Только функция InternetOpen использует этот флаг.
Указывает, что функция должна использовать копию ресурса, который в настоящее время находится в кэше Интернета. Дата окончания срока действия и другие сведения о ресурсе не проверяются. Если запрошенный элемент не найден в кэше Интернета, система попытается найти ресурс в сети. Это значение появилось в Microsoft Internet Обозреватель 5 и связано с операциями "Вперед" и "Назад" Обозреватель Интернета.
При необходимости приложение перезагрузит ресурс, если срок действия не истек и время последнего изменения не было возвращено, когда ресурс был сохранен в кэше.
Отклоняет любые попытки функции сохранить данные, скачанные из Интернета, в кэше. Этот флаг необходим, если приложение не хочет, чтобы скачанные ресурсы хранились локально.
Запрещает приложению отправлять запросы в сеть. Все запросы разрешаются с помощью ресурсов, хранящихся в кэше. Если ресурс отсутствует в кэше, возвращается подходящая ошибка, например ERROR_FILE_NOT_FOUND.
Принудительно разрешает запрос сервером-источником, даже если на прокси-сервере существует кэшированная копия. Функция InternetOpenUrl (только для HTTP- и HTTPS-запросов) и функция HttpOpenRequest используют этот флаг.
Заставляет приложение выполнить условную загрузку ресурса из Интернета. Если версия, хранящейся в кэше, является текущей, сведения скачиваются из кэша. В противном случае данные будут перезагружены с сервера.
Функции постоянного кэширования
Клиенты, которым требуются службы постоянного кэширования, используют функции постоянного кэширования, чтобы разрешить приложениям сохранять данные в локальной файловой системе для последующего использования, например в ситуациях, когда канал с низкой пропускной способностью ограничивает доступ к данным или доступ недоступен вообще.
Функции кэша обеспечивают постоянное кэширование и просмотр в автономном режиме. Если флаг INTERNET_FLAG_NO_CACHE_WRITE явно не указывает отсутствие кэширования, функции кэшируют все данные, скачанные из сети. Ответы на данные POST не кэшируются.
Использование функций кэша постоянных URL-адресов
Следующие функции постоянного кэша URL-адресов позволяют приложению получать доступ к информации, хранящейся в кэше, и управлять ими.
Обе функции хранят структуру INTERNET_CACHE_ENTRY_INFO в буфере. Размер этой структуры зависит от каждой записи. Если размер буфера, переданный любой из функций, недостаточен, функция завершается сбоем и GetLastError возвращает ERROR_INSUFFICIENT_BUFFER. Переменная размера буфера содержит размер буфера, необходимый для получения этой записи кэша. Необходимо выделить буфер размера, указанного переменной размера буфера, и функция должна вызываться снова с новым буфером.
Структура INTERNET_CACHE_ENTRY_INFO содержит размер структуры, URL-адрес кэшированных сведений, имя локального файла, тип записи кэша, количество использования, скорость попаданий, размер, время последнего изменения, срок действия, последний доступ, время последней синхронизации, сведения о заголовке, размер сведений о заголовке и расширение имени файла.
Функция FindFirstUrlCacheEntry принимает шаблон поиска, буфер, в котором хранится структура INTERNET_CACHE_ENTRY_INFO , и размер буфера. В настоящее время реализован только шаблон поиска по умолчанию, который возвращает все записи кэша.
После перечисления кэша приложение должно вызвать FindCloseUrlCache , чтобы закрыть дескриптор перечисления кэша.
В следующем примере в поле списка отображается URL-адрес каждой записи кэша , IDC_CacheList. Для первоначального выделения буфера используется MAX_CACHE_ENTRY_INFO_SIZE, так как в ранних версиях API WinINet кэш не перечисляется должным образом. Более поздние версии правильно перечисляют кэш, и размер кэша не ограничен. Все приложения, которые выполняются на компьютерах с версией API WinINet из Интернета Обозреватель 4.0, должны выделять буфер требуемого размера. Дополнительные сведения см. в разделе Использование буферов.
int WINAPI EnumerateCacheOld(HWND hX)
{
DWORD dwEntrySize;
LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry;
DWORD MAX_CACHE_ENTRY_INFO_SIZE = 4096;
HANDLE hCacheDir;
int nCount=0;
SendDlgItemMessage(hX,IDC_CacheList,LB_RESETCONTENT,0,0);
SetCursor(LoadCursor(NULL,IDC_WAIT));
dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];
lpCacheEntry->dwStructSize = dwEntrySize;
again:
hCacheDir = FindFirstUrlCacheEntry(NULL,
lpCacheEntry,
&dwEntrySize);
if (!hCacheDir)
{
delete[]lpCacheEntry;
switch(GetLastError())
{
case ERROR_NO_MORE_ITEMS:
TCHAR tempout[80];
_stprintf_s(tempout,
80,
TEXT("The number of cache entries = %d \n"),
nCount);
MessageBox(hX,tempout,TEXT("Cache Enumeration"),MB_OK);
FindCloseUrlCache(hCacheDir);
SetCursor(LoadCursor(NULL,IDC_ARROW));
return TRUE;
break;
case ERROR_INSUFFICIENT_BUFFER:
lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO)
new char[dwEntrySize];
lpCacheEntry->dwStructSize = dwEntrySize;
goto again;
break;
default:
ErrorOut( hX,GetLastError(),
TEXT("FindNextUrlCacheEntry Init"));
FindCloseUrlCache(hCacheDir);
SetCursor(LoadCursor(NULL,IDC_ARROW));
return FALSE;
}
}
SendDlgItemMessage(hX,IDC_CacheList,LB_ADDSTRING,
0,(LPARAM)(lpCacheEntry->lpszSourceUrlName));
nCount++;
delete (lpCacheEntry);
do
{
dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;
lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];
lpCacheEntry->dwStructSize = dwEntrySize;
retry:
if (!FindNextUrlCacheEntry(hCacheDir,
lpCacheEntry,
&dwEntrySize))
{
delete[]lpCacheEntry;
switch(GetLastError())
{
case ERROR_NO_MORE_ITEMS:
TCHAR tempout[80];
_stprintf_s(tempout,
80,
TEXT("The number of cache entries = %d \n"),nCount);
MessageBox(hX,
tempout,
TEXT("Cache Enumeration"),MB_OK);
FindCloseUrlCache(hCacheDir);
return TRUE;
break;
case ERROR_INSUFFICIENT_BUFFER:
lpCacheEntry =
(LPINTERNET_CACHE_ENTRY_INFO)
new char[dwEntrySize];
lpCacheEntry->dwStructSize = dwEntrySize;
goto retry;
break;
default:
ErrorOut(hX,
GetLastError(),
TEXT("FindNextUrlCacheEntry Init"));
FindCloseUrlCache(hCacheDir);
return FALSE;
}
}
SendDlgItemMessage(hX,
IDC_CacheList,LB_ADDSTRING,
0,
(LPARAM)(lpCacheEntry->lpszSourceUrlName));
nCount++;
delete[] lpCacheEntry;
} while (TRUE);
SetCursor(LoadCursor(NULL,IDC_ARROW));
return TRUE;
}
Получение сведений о входных данных кэша
Функция GetUrlCacheEntryInfo позволяет получить структуру INTERNET_CACHE_ENTRY_INFO для указанного URL-адреса. Эта структура содержит размер структуры, URL-адрес кэшированных сведений, имя локального файла, тип записи кэша, количество использования, скорость попаданий, размер, время последнего изменения, срок действия, последний доступ, время последней синхронизации, сведения о заголовке, размер сведений о заголовке и расширение имени файла.
GetUrlCacheEntryInfo принимает URL-адрес, буфер для структуры INTERNET_CACHE_ENTRY_INFO и размер буфера. Если URL-адрес найден, сведения копируются в буфер. В противном случае функция завершается сбоем, а GetLastError возвращает ERROR_FILE_NOT_FOUND. Если размер буфера недостаточен для хранения сведений о записи в кэше, функция завершается сбоем и GetLastError возвращает ERROR_INSUFFICIENT_BUFFER. Размер, необходимый для получения сведений, хранится в переменной размера буфера.
GetUrlCacheEntryInfo не выполняет синтаксический анализ URL-адресов, поэтому URL-адрес, содержащий привязку (#), не будет найден в кэше, даже если ресурс кэширован. Например, если URL-адрес "https://example.com/example.htm#sample" передается, функция возвращает ERROR_FILE_NOT_FOUND, даже если "https://example.com/example.htm" находится в кэше.
В следующем примере извлекаются сведения о записи кэша для указанного URL-адреса. Затем функция отображает сведения о заголовке в поле ввода IDC_CacheDump .
int WINAPI GetCacheEntryInfo(HWND hX,LPTSTR lpszUrl)
{
DWORD dwEntrySize=0;
LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry;
SetCursor(LoadCursor(NULL,IDC_WAIT));
if (!GetUrlCacheEntryInfo(lpszUrl,NULL,&dwEntrySize))
{
if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
{
ErrorOut(hX,GetLastError(),TEXT("GetUrlCacheEntryInfo"));
SetCursor(LoadCursor(NULL,IDC_ARROW));
return FALSE;
}
else
lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO)
new char[dwEntrySize];
}
else
return FALSE; // should not be successful w/ NULL buffer
// and 0 size
if (!GetUrlCacheEntryInfo(lpszUrl,lpCacheEntry,&dwEntrySize))
{
ErrorOut(hX,GetLastError(),TEXT("GetUrlCacheEntryInfo"));
SetCursor(LoadCursor(NULL,IDC_ARROW));
return FALSE;
}
else
{
if ((lpCacheEntry->dwHeaderInfoSize)!=0)
{
LPSTR(lpCacheEntry->lpHeaderInfo)
[lpCacheEntry->dwHeaderInfoSize]=TEXT('\0');
SetDlgItemText(hX,IDC_Headers,
lpCacheEntry->lpHeaderInfo);
}
else
{
SetDlgItemText(hX,IDC_Headers,TEXT("None"));
}
SetCursor(LoadCursor(NULL,IDC_ARROW));
return TRUE;
}
}
CreateUrlCacheEntry принимает URL-адрес, ожидаемый размер файла и расширение имени файла. Затем функция создает локальное имя файла для сохранения записи кэша, соответствующей URL-адресу и расширению имени файла.
Используя имя локального файла, запишите данные в локальный файл. После записи данных в локальный файл приложение должно вызвать CommitUrlCacheEntry.
CommitUrlCacheEntry принимает URL-адрес, имя локального файла, срок действия, время последнего изменения, тип записи кэша, сведения о заголовке, размер сведений о заголовке и расширение имени файла. Затем функция кэширует данные в файле, указанном в хранилище кэша, и связывает их с заданным URL-адресом.
В следующем примере используется имя локального файла, созданное при предыдущем вызове CreateUrlCacheEntry, хранящееся в текстовом поле IDC_LocalFile, для хранения текста из текстового поля IDC_CacheDump в записи кэша. После записи данных в файл с помощью fopen, fprintf и fclose запись фиксируется с помощью CommitUrlCacheEntry.
Функция DeleteUrlCacheEntry принимает URL-адрес и удаляет связанный с ним файл кэша. Если файл кэша не существует, функция завершается ошибкой, и GetLastError возвращает ERROR_FILE_NOT_FOUND. Если файл кэша в настоящее время заблокирован или используется, функция завершается сбоем и GetLastError возвращает ERROR_ACCESS_DENIED. Файл удаляется при разблокировке.
RetrieveUrlCacheEntryStream не выполняет синтаксический анализ URL-адресов, поэтому URL-адрес, содержащий привязку (#), не будет найден в кэше, даже если ресурс кэширован. Например, если URL-адрес "https://example.com/example.htm#sample" передается, функция возвращает ERROR_FILE_NOT_FOUND, даже если "https://example.com/example.htm" находится в кэше.
После использования сведений в файле приложение должно вызвать UnlockUrlCacheEntryFile , чтобы разблокировать файл.
Группы кэша
Чтобы создать группу кэша, необходимо вызвать функцию CreateUrlCacheGroup , чтобы создать GROUPID для группы кэша. Записи можно добавить в группу кэша, указав URL-адрес записи кэша и флаг INTERNET_CACHE_GROUP_ADD для функции SetUrlCacheEntryGroup . Чтобы удалить запись кэша из группы, передайте URL-адрес записи кэша и флаг INTERNET_CACHE_GROUP_REMOVE в SetUrlCacheEntryGroup.
Обработка структур со сведениями о переменном размере
Кэш может содержать сведения о переменном размере для каждого сохраненного URL-адреса. Это отражено в структуре INTERNET_CACHE_ENTRY_INFO . Когда функции кэша возвращают эту структуру, они создают буфер, который всегда имеет размер INTERNET_CACHE_ENTRY_INFO плюс любые сведения о размере переменных. Если элемент указателя не имеет значения NULL, он указывает на область памяти сразу после структуры. При копировании буфера, возвращаемого функцией, в другой буфер элементы указателя должны быть зафиксированы, чтобы они указывали на соответствующее место в новом буфере, как показано в следующем примере.
Некоторые функции кэша завершаются сбоем с сообщением об ошибке ERROR_INSUFFICIENT_BUFFER, если указать буфер, который слишком мал, чтобы содержать сведения о записи кэша, полученные функцией. В этом случае функция также возвращает необходимый размер буфера. Затем можно выделить буфер соответствующего размера и снова вызвать функцию.
Примечание
WinINet не поддерживает реализации сервера. Кроме того, его не следует использовать из службы. Для серверных реализаций или служб используйте службы Microsoft Windows HTTP (WinHTTP).