Подписка

Проекты

Сборник идей для разработок в Delphi и использования их в Интернет. Участвуй в работе коллективного разума!

Google API в Delphi - проект с открытым исходным кодом.


А тут я коплю на лицензию Delphi 2011. Сумма пожертвования не фиксирована.

Друзья блога

Блоги и сообщества

DelphiFeeds.ru - Все Delphi-блоги Рунета О раскрутке блога по программированию Сообщество умных людей VR-Online.RU Бесплатный журнал для программистов и всех, кто интересуется IT Статьи и уроки по Delphi Статьи по Delphi

Счётчики


Анализ веб сайтов

Рейтинг блогов




Система Orphus

  • 15Feb

    Сегодня решил дописать свой THTTPSender, который использует в работе WinInet.  Первое, что необходимо было сделать – это научиться правильно читать код ответа сервера для того, чтобы проолжить работу над Google Data API. При этом важно было не только “поймать” код 200 или 400, но и определять момены, когда сервер выдает коды 301 или 302.  Обычно при работе с WinInet этот момент (определение кодов перенаправления) опускается, т.к. чаще всего удобно, чтобы перенаправление происходило автоматически. Сегодня разберемся как отлавливать все коды стауса и чиать заголовки сервера. ' ' Для того, чтобы получить какую либо служебную информацию от сервера мы можем воспользоваться методом HttpQueryInfo. Рассмотрим входные параметры функции:

    • hRequest - Handle, который мы получаем при выполнении HttpOpenRequest или InternetOpenUrl.
    • dwInfoLevel - комбинация флагов, каждый из которых указывает, какая информация нам необходима
    • lpvBuffer - указатель на буфер в котоый будет происходить запись данных.
    • lpdwBufferLength - размер буфера
      lpdwIndex - индекс заголовка

    Сама функция HttpQueryInfo работает следующим образом: при выполнении происходит попытка чтения в буфер запрошенной информации. Если размер буфера оказывается мал, то вызывается исключение ERROR_INSUFFICIENT_BUFFER и переменная lpdwBufferLength будет содержать необходимую размерность буфера для приёма всех данных. В случае, если мы запрашиваем информацию, которую сервер вернуть не в состоянии, вызывается исключение ERROR_HTTP_HEADER_NOT_FOUND.

    Немного поэкспериментировав с HttpQueryInfo обнаружил следующее: по документации MSDN для успешного выполнения функции необходимо указывать хэндл, который мы берем из HttpOpenRequest или InternetOpenUrl. Если использовать InternetOpenUrl, то  так и есть – функция отрабатывает как надо и возвращает результат. Если я использую HttpOpenRequest, то функция отказывается возвращать данные (при этом GetLastError ничего не выдает), но срабатывает после выполнения метода HttpSendRequest. Не думаю, что это глюк, но учитывать этот момент стоит.

    Теперь, что касается исключение ERROR_HTTP_HEADER_NOT_FOUND. На это исключение можно довольно легко налететь. Например, мы запрашиваем информацию о последнем изменении страницы. Для этого мы устанавливаем флаг HTTP_QUERY_LAST_MODIFIED и пробуем выполнить метод. Если в заголовках сервера нет заголовка Last-Modified, то функция вернет False и в результате выполнения GetLastError мы получим исключение ERROR_HTTP_HEADER_NOT_FOUND. Поэтому следует очень осторожно пользоваться методом, когда есть вероятность того, что в заголовках нет необходимой информации.

    Чтобы получать всю информацию от сервера, которую он выдает, я пользуюсь флагом HTTP_QUERY_RAW_HEADERS_CRLF, при этом возвращается строка, содержащая все заголовки сервера и каждый заголовок разделен символами CR/LF (#10#13), что удобно, например, для использования результата в списках TStringList.

    Теперь перейдем непосредственно к программированию. Итак, пишем функцию для получения информации сервера. Назовем её, например GetQueryInfo. В процессе работы нам может потребоваться:

    1. Получние како-либо конкретной информации, например, код ответа сервера.
    2. Получение всей информации – всех заголовков.

    Соответственно, в первом случае, будет излишним взводить HTTP_QUERY_RAW_HEADERS_CRLF (код статуса занимает 6-8 байт, а заголовки могу насчитывать килобайты информации). Следовательно в качестве входных парамеров функции будут выступать:

    1. Хэндл (hRequest)
    2. Флаг (dwInfoLevel) тип параметра – integer.

    Теперь по самому алгоритму. Будем делать так:

    1. Задаем буферу минимальный размер, которого будет достаточно, чтобы прочитать код статуса (сама функция возвращает минимальное значение 8 байт)
    2. Пробуем выполнить функцию HttpQueryInfo
    3. Если возвращается ERROR_INSUFFICIENT_BUFFER,
      тоизменяем размер буфера и повторно вызываем HttpQueryInfo.
    4. Если возвращается код ошибки отличный от 122 (ERROR_INSUFFICIENT_BUFFER), то завершаем работу без повторного вызова HttpQueryInfo.

    Все вышесказанное в Delphi выглядит следующим образом:

    function THTTPSender.GetQueryInfo(hRequest: Pointer; Flag: integer): string;
    var code: String;
        size,index:Cardinal;
    begin
      SetLength(code,8);//достаточная длина для чтения статус-кода
      size:=Length(code);
      index:=0;
      if HttpQueryInfo(hRequest, Flag ,PChar(code),size,index)then
        Result:=Code
      else
        if GetLastError=ERROR_INSUFFICIENT_BUFFER then //увеличиваем буффер
          begin
            SetLength(code,size);
            size:=Length(code);
            if HttpQueryInfo(hRequest,Flag,PChar(code),size,index) then
              Result:=code;
          end
      else
        begin
          FErrorCode:=GetLastError;
          Result:='';
        end;
    end;

    Теперь используем эту функцию для чтения и сохранения заголовков сервера.  Для получения всех заголовков сервера необходимо сделать следующий вызов:

    GetQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF)

    На выходе – строка. Для того, чтобы не вызывать метод несколько раз для получения информации, достаточно разобрать полученные заголовки и гарантированно мы здесь можем получить:

    • данные по протоколу
    • код статуса сервера
    • ответ сервера (текст)
    • если код статуса 301 или 302 – получить адрес перенаправления (заголовок Location).

    Онако здесь следует учесть один момент. Заключается он в следующем:

    чтобы отлавливать коды 301 и 302 при вызове метода HttpOpenRequest обязательно надо взводить флаг INTERNET_FLAG_NO_AUTO_REDIRECT, ктороый останавливает автоперенаправление на адрес.

    После взведения флага можно спокойно читать все статус-коды. Например с использованием следующей процедуры:

    procedure THTTPSender.ParseHeaders(HeasersStr: string);
    var i:integer;
        s: string;
    begin
      if not Assigned(FHeaders)then FHeaders:=TStringList.Create;
      FHeaders.Clear;
      FHeaders.Text:=HeasersStr;
      FHeaders.Delete(FHeaders.Count-1); //последний элемент содержит всегда CRLF
     
      if FHeaders.Count>0 then
        begin
    //читаем данные о протоколе, статус-коде и ответе сервера
          S:=FHeaders[0];
          FProtocol:=copy(s,1,pos(' ',s)-1);
          Delete(s,1,Length(FProtocol)+1);
          FProtocol:=copy(FProtocol,1,pos('/',FProtocol)-1);
          FResponseCode:=StrToInt(copy(s,1,pos(' ',s)-1));
          Delete(s,1,Length(IntToStr(FResponseCode))+1);
          FResponseText:=Trim(s);
    //если было перенаправление, то читаем адрес
         if (ResponseCode=HTTP_STATUS_MOVED)or(ResponseCode=HTTP_STATUS_REDIRECT) then
           for I := 0 to FHeaders.Count - 1 do
             begin
               if pos('location:',lowercase(FHeaders[i]))>0 then
                 begin
                   FLocation:=LowerCase(FProtocol)+'//'+FDomain+'/'+Trim(copy(FHeaders[i],10,length(FHeaders[i])-9));
                   break;
                 end;
             end;
      end;
    end;

    Таким образом, вместо того, чтобы вызывать HttpQueryInfo
    несколько раз для получения необходимой информации, мы вызываем метод всего 1-2 раза и читаем сразу все. Можно дописать приведенную выше процедуру и получать, например, данные по установленным кукам.

    ------------------------------
    Вы покупаете лицензионный софт? Воспользуйтесь сайтом mirsofta.com.ua для покупки любого программного обеспечения от простой утилиты до операционной системы или CAD.
    ------------------------------

    Related posts:

    1. Google Celendar API в Delphi. Начало работы.
    2. Google API. Интерфейс ClientLogin для Delphi.

    Автор Vlad в 6:54 pm

    Метки: , ,

1 Comment

WP_Cloudy

Ваш ответ

Внимание: Все комментарии модерируются, и это может вызвать задержку их публикации. Отправлять комментарий заново не требуется.

Пожалуйста, заключайте исходный код в тэги [code][/code].