Что такое HTTP HEAD запрос и как его использовать для проверки изменений файла?
Что проверяют
Знаете ли вы методы HTTP дальше GET и POST и понимаете ли, зачем клиенту заголовки без тела. В iOS вопрос упирается в трафик: приложение регулярно обновляет каталог или конфигурацию, и разница между «скачали и сравнили» и «спросили, изменилось ли» видна на мобильной сети.
Как отвечать
HEAD это тот же GET, но сервер обязан вернуть только заголовки: статус, Content-Length, Content-Type, Last-Modified, ETag. Тела нет, запрос дешёвый. Классический сценарий: сохранили метку версии, перед загрузкой спросили HEAD, сравнили, качаем только при расхождении.
Сильный ответ идёт дальше и говорит, что чаще уместнее условный GET. Клиент отправляет If-None-Match с сохранённым ETag (или If-Modified-Since с датой), сервер отвечает 304 без тела либо сразу 200 с новым содержимым. Это одно обращение вместо двух, и тело приходит тогда же, когда стало известно об изменении.
var request = URLRequest(url: url)
request.httpMethod = "HEAD"
request.cachePolicy = .reloadIgnoringLocalCacheData
let (_, response) = try await URLSession.shared.data(for: request)
let etag = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "ETag")Где спотыкаются
Достают заголовок из словаря всех полей по ключу в своём регистре. Имена заголовков регистронезависимы, сервер вправе прислать etag строчными, и словарный доступ молча вернёт nil; для этого есть отдельный метод поиска поля по имени без учёта регистра.
Полагаются на дату модификации как на точный признак. Точность в секундах, время файла меняется при выкладке у всего содержимого сразу, а часы сервера и клиента расходятся. ETag надёжнее.
Забывают про кэш и посредников. Сессия может отдать ответ из своего кэша, не сходив в сеть, а прокси и CDN на HEAD иногда отвечают иначе, чем на GET, вплоть до отсутствующей длины содержимого.