У меня Indy 10.6.2.5366 и Delphi Tokyo 10.2 с обновлением 3.
В ответ на HTTPS POST
CookieManager сообщает, что файлов cookie нет, но когда я делаю тот же запрос в почтальоне, в ответе появляется файл cookie с именем «ROUTEID».
но когда я делаю тот же запрос в Delphi, файл cookie «ROUTEID» отсутствует.
мне нужно сохранить файлы cookie, потому что они содержат информацию для аутентификации, которую мне нужно отправлять в последующих запросах, как утверждает Реми Лебо в этом посте.
Должно быть, я делаю что-то не так, потому что в этом другом посте Реми говорит, что TCookieManager был полностью переписан с нуля, но что мне не хватает?
Я заметил, что почтальон показывает 10 заголовков в ответе, а Delphi показывает только 8 в TIdHTTP.Response.RawHeaders
Я знаю, что код ответа моего запроса 401, но даже при несанкционированной ошибке в ответе присутствует куки.
наконец, вот мой код:
procedure TestMethod(AUrl, ABody: string);
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
LStreamRequestBody: TStringStream;
LReturnBody: string;
LCookieList: TIdCookieList;
n: Integer;
begin
HTTP := TIdHTTP.Create(nil);
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
LStreamRequestBody := TStringStream.Create(ABody, TEncoding.UTF8);
try
IdOpenSSLSetLibPath(Utils.Global.SSLLibPath);
SSL.SSLOptions.Method := sslvSSLv23;
SSL.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1];
SSL.SSLOptions.Method := sslvSSLv23;
HTTP.IOHandler := SSL;
HTTP.Response.ContentType := 'application/json;charset=utf-8';
HTTP.Request.CustomHeaders.FoldLines := True;
HTTP.Request.Accept := '*/*';
HTTP.Request.ContentType := 'application/json';
HTTP.Request.Connection := 'keep-alive';
HTTP.Request.AcceptEncoding := 'gzip, deflate, br';
HTTP.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
HTTP.CookieManager := TIdCookieManager.Create(nil);
HTTP.AllowCookies := True;
HTTP.HandleRedirects := True;
try
LReturnBody := HTTP.Post(AUrl, LStreamRequestBody);
Except
on e: EIdHTTPProtocolException do
begin
LCookieList := HTTP.CookieManager.CookieCollection.LockCookieList(caRead);
try
for n := 0 to LCookieList.Count - 1 do
begin
end;
finally
HTTP.CookieManager.CookieCollection.UnlockCookieList(caRead);
end;
end;
end;
finally
LStreamRequestBody.Free;
HTTP.Free;
SSL.Free;
end;
end;
В ответ на HTTPS POST CookieManager сообщает, что файлов cookie нет, но когда я делаю тот же запрос в почтальоне, в ответе появляется файл cookie с именем «ROUTEID»... но когда я делаю точно такой же запрос в Delphi, нет файла cookie «ROUTEID».
Тогда проблема не в самом Инди. Сервер изначально не отправляет файлы cookie.
Я заметил, что почтальон показывает 10 заголовков в ответе, но Delphi показывает только 8 в TIdHTTP.Response.RawHeaders.
Это означает, что сервер отправляет разные ответы разным пользовательским агентам. Смотрите этот вопрос , на который я ответил буквально вчера, который страдал от подобной проблемы. Но в двух словах:
Многие серверы чувствительны к запрашивающему агенту и отправляют разные данные разным агентам. Такие серверы нередко отклоняют/не распознают значение Indy по умолчанию
User-Agent
....
Когда вы сравниваете запросы Curl [или, в данном случае, Postman] с другими HTTP-библиотеками, вы всегда должны стремиться к тому, чтобы запросы были как можно более идентичными, чтобы исключить любые возможные различия, которые могут сбить с толку серверы. А когда между похожими запросами существуют различия в поведении, обычно виноват
User-Agent
[заголовок запроса].
Я вижу, вы устанавливаете для свойства TIdHTTP.Request.UserAgent
значение, имитирующее Firefox. Возникнет ли у вас та же проблема, если вместо этого вы настроите имитацию Почтальона? Я считаю, что значение User-Agent
Postman по умолчанию — это что-то вроде PostmanRuntime/<version>
. Возникнет ли у вас та же проблема, если вы настроите Postman на использование того же значения Firefox User-Agent
, что и TIdHTTP
?
Кстати, это связано не с вашей проблемой с файлами cookie, а с представленным вами кодом в целом:
вам не следует вызывать IdOpenSSLSetLibPath()
при каждом HTTP-запросе. Вызовите его один раз, желательно при запуске приложения.
не используйте свойства SSLOptions.Method
и SSLOptions.SSLVersions
SSLIOHandler вместе. Они являются взаимоисключающими, установка одного обновляет другой. Установив Method
на sslvSSLv23
, вы включаете SSL v2–v3 в дополнение к TLS v1.0–1.2. Больше не включайте SSL. Остановитесь только на свойстве SSLVersions
.
не устанавливайте свойство TIdHTTP.Response.ContentType
при отправке запроса. Это просто бесполезно.
свойство TIdHTTP.Request.CustomHeaders.FoldLines
должно иметь значение False, поскольку протокол HTTP больше не поддерживает свертывание заголовков, начиная с RFC 7230.
не устанавливайте свойство TIdHTTP.Request.AcceptEncoding
вручную, если вы не готовы декодировать необработанное тело ответа вручную. Indy изначально поддерживает сжатие gzip
и deflate
через свойство TIdHTTP.Compressor
, но в настоящее время не поддерживает br
. Вы даете серверу разрешение на сжатие ответа таким образом, чтобы TIdHTTP
не могло быть распаковано автоматически (например, на вашем снимке экрана показано, что ответ сжат с помощью gzip). Правильный подход — включить Compressor
и позволить TIdHTTP
управлять AcceptEncoding
за вас, исходя из реальных возможностей компрессора.
вы сливаете объект TIdCookieManager
. TIdHTTP
не становится владельцем предоставленного пользователем CookieManager. Если вы его не предоставите, TIdHTTP
просто создаст его внутри компании и возьмет на себя ответственность за него.