Лазарус + Synapse

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Лазарус + Synapse

Сообщение yante » 10.08.2024 22:47:53

Я прошу прощения, может кто знает, как считывать данные с dadata.ru из Лазаруса с помощью Synapse - спокойно считываю через Питон, но не могу считать Лазарусом...
Вот код, в нем много отладочных сообщений...
Получаю ResultString = 200, но возвращает пустую строку... :(

Код: Выделить всё
function GetDaData(URL, ContentType, Accept, Token, Body: string): string;
var
    IdHTTP1: THTTPSend;
    StringStream: TStringStream;
    tmpBool : Boolean;
begin
    IdHTTP1 := THTTPSend.Create;

    try
        IdHTTP1.Headers.Add('Authorization: ' + 'Token ' + Token);
        IdHTTP1.Headers.Add('X-Secret: ' + 'Secret_API');
        IdHTTP1.Headers.Add('Accept: ' + Accept);
        IdHTTP1.Headers.Add('Content-Type: ' + ContentType);
//        IdHTTP1.Headers.Add('Content-Type:' + 'application/json');
//        IdHTTP1.Headers.Add('Accept:' + 'application/json');

//        IdHTTP1.Headers.Add('X-Secret: Secret_API');
//        IdHTTP1.MimeType := 'application/x-www-form-urlencoded';
        IdHTTP1.MimeType  := ContentType;
//        IdHTTP1.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36';
        IdHTTP1.UserAgent := 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0';

        ShowMessage('Yes = ' + ' / ' + URL +  LE
                    + IdHTTP1.ResultString + LE
                    + (IdHTTP1.Cookies.Text) + LE
                    + (IdHTTP1.Headers.Text)
        );
        StringStream := TStringStream.Create('');
        StringStream.WriteString(UTF8Encode(Body));
        ShowMessage(StringStream.DataString);
        IdHTTP1.Document.LoadFromStream(StringStream);

        tmpBool := IdHTTP1.HTTPMethod('post', URL);   // , StringStream
        ShowMessage(IdHTTP1.Document.ReadAnsiString);

        if tmpBool = true then begin
          ShowMessage('Yes = ' + ' / ' + URL +  LE
                      + IdHTTP1.ResultString + LE
                      + IntToStr(IdHTTP1.ResultCode) + LE
                      + (IdHTTP1.Cookies.Text) + LE
                      + (IdHTTP1.Headers.Text)
          );
          Result := IdHTTP1.ResultString;
        end
        else begin
          ShowMessage('No = ' + IdHTTP1.ResultString + LE
                      + (IdHTTP1.ResultString));
          Result := IdHTTP1.ResultString;
        end;
    finally
        StringStream.Free;
        IdHTTP1.Free;
    end;
end;
yante
незнакомец
 
Сообщения: 4
Зарегистрирован: 10.12.2020 12:54:53

Re: Лазарус + Synapse

Сообщение Alex2013 » 11.08.2024 10:14:25

Проблема ssl ? ssleay32.dll и libeay32.dll доступны ? ( и актуальных версий )
(По умолчанию юзаются те что в лазарус или в системе но лучше дажать свои в папке проекта рядом с EXE-шником + есть 32-х и 64-х разрядные версии )
https://wiki.lazarus.freepascal.org/Synapse/ru
Вы можете использовать поддержку OpenSSL, CryptLib, StreamSecII или OpenStreamSecII SSL с Synapse. По умолчанию поддержка SSL не используется.

Ps
http://www.delphikingdom.com/asp/viewit ... logid=1336
ИМХО перебор...
Но рецепт в принципе реальный . ( Суть прикола (если я верно понял) в том что если DDL с именем ХХХ.DLL (при статическом линке) уже в памяти то её может повторно не загружать, однако (имхо) что-бы это преодолеть достаточно сделать динамическую загрузку да и просто переименовать файл DDL (и поправить исходники Synapse) по идее можно.)
Alex2013
долгожитель
 
Сообщения: 3048
Зарегистрирован: 03.04.2013 11:59:44

Re: Лазарус + Synapse

Сообщение *Rik* » 11.08.2024 11:40:18

Alex2013 писал(а):Проблема ssl ? ssleay32.dll и libeay32.dll доступны ? ( и актуальных версий )

Synapse использует OpenSSL, и компилировать его (synapse) в свой проект, нужно с поддержкой конкретной версии, по умолчанию там версия 1.0, с которой уже ни куда не законнектишься, для примера у меня используется OpenSSL 1.1, под windows это будут 2 либы, можно скачать инсталлятор с официального сайта и установить всё в системный каталог, но япредпочитаю таскать либы с собой без установок:
libssl-1_1-x64.dll
libcrypto-1_1-x64.dll
По линуксом соответственно в системном каталоге библиотеки с именами по умолчнию, устанавливаются из репозитория при установке OpenSSL 1.1 штатными средствами:
libssl.so.1.1
libcrypto.so.1.1
пробовал использовать synapse с OpenSSL 3, откатился обратно, не везде поддерживается.
Для использования нужной версии в своем проекте просто добавьте в раздел uses:
Код: Выделить всё
uses httpsend, FileUtil, ftpsend, pop3send, mimemess, mimepart,
  synachar, imapsend, dpEvnthadlrs, synaser, Forms, LazUTF8,
  ssl_openssl11, ssl_openssl11_lib;

Эти файлы: ssl_openssl11, ssl_openssl11_lib поставляются с исходниками Synapse, соответственно если нужно добавить поддержку OpenSSL 3, то файлы нужно будет заменить на ssl_openssl3, ssl_openssl3_lib.

Если дело в ssl, то скорее всего вы бы не смогли сам запрос выполнить, если запрос выполняется, то дело не в ssl.

Ниже вытащил пример нормализации адреса через dadata из своего рабочего проекта c использованием Synapse, но код на Дизель-Паскале.
Код: Выделить всё
method TNormalAdres.ExecNormalDadata(Adres, Token, Key: string): Boolean;
var
  HTTP: THTTPSend;
  //SL: TStringList;
  Arr: TJSONArray;
  Parser: TJSONParser;
  OBJ: TJSONObject;
begin
  Result = False;
  Clear;

  Checked = False;
  qc_complete = -1;
  qc_house = -1;
  qc = -1;

  URL = 'https://cleaner.dadata.ru/api/v1/clean/address';
  HTTP = THTTPSend.Create;
  Arr = TJSONArray.Create;
  try
    Arr.AddStr(Adres);
    Request.Text = Arr.AsJSON;

    //AddInfoText(SL.Text);

    //AddInfoText('Отправка запроса');

    HTTP.Headers.Clear;
    HTTP.MimeType = 'application/json';
    HTTP.Headers.Add('Content-Type: application/json');
    HTTP.Headers.Add('Accept: application/json');
    HTTP.Headers.Add('Authorization: Token ' + Token);
    HTTP.Headers.Add('X-Secret: ' + Key);
    Request.SaveToStream(HTTP.Document);
    HTTP.Document.Seek(0, soBeginning);
    HTTP.HTTPMethod('POST', URL);


    if HTTP.ResultCode = 200 then
      HTTP.Document.Seek(0, soBeginning);
      Respons.LoadFromStream(HTTP.Document);
      OBJ = nil;
      Parser = TJSONParser.Create(Respons.Text);
      try
        Arr.Free;
        Arr = nil;

        Arr = Parser.Parse As TJSONArray;
        OBJ = Arr.Objects[0];
        qc_complete = OBJ.Integers['qc_complete'];
        qc_house = OBJ.Integers['qc_house'];
        qc = OBJ.Integers['qc'];
        qc_geo = OBJ.Integers['qc_geo'];

        if not OBJ.Nulls['postal_code'] then
          PIndex = OBJ.Strings['postal_code'];
        end;
        if not OBJ.Nulls['region_with_type'] then
          FRegion = OBJ.Strings['region_with_type'];
        end;
        if not OBJ.Nulls['area_with_type'] then
          FArea = OBJ.Strings['area_with_type'];
        end;
        if not OBJ.Nulls['city'] then
          FPlase = OBJ.Strings['city'] + ' ' + OBJ.Strings['city_type'];
          PlaceGuid = OBJ.Strings['city_fias_id'];
        end;
        if not OBJ.Nulls['settlement'] then
          FLocation = OBJ.Strings['settlement'] + ' ' + OBJ.Strings['settlement_type'];
          if PlaceGuid = '' then
            PlaceGuid = OBJ.Strings['settlement_fias_id'];
          end;
          if FPlase = '' then
            FPlase = FLocation;
            FLocation = '';
          end;
        end;
        if not OBJ.Nulls['street'] then
          FStreet = OBJ.Strings['street'] + ' ' + OBJ.Strings['street_type'];
        end;
        if not OBJ.Nulls['house'] then
          FHouse = OBJ.Strings['house'];
        end;
        if not OBJ.Nulls['block'] then
          FCorpus = OBJ.Strings['block'];
        end;
        if not OBJ.Nulls['flat'] then
          FRoom = OBJ.Strings['flat'];
        end;
        if not OBJ.Nulls['postal_box'] then
          AdresTypeID = 1;
          AdresType = 'PO_BOX';
          FNumAdresType = OBJ.Strings['postal_box'];
        end;
        case qc of
          1:
          begin
              Err = 'Остались лишние части';
              if not OBJ.Nulls['unparsed_parts'] then
                Err = Err + ''#13#10;
                UnparsedParts = OBJ.Strings['unparsed_parts'];
                Err = Err + UnparsedParts;
                Err = Err + ''#13#10;
              end;
          end;
          2: Err = 'Адрес пустой или заведомо мусорный или недостаточно данных для разбора';
          3: Err = 'Есть альтернативные варианты адреса';
        end;

        case qc_complete of
          0: begin
            Checked = True;
            Result = True;
          end;
          1: Err += 'Нет региона';
          2: Err += 'Нет города';
          3: Err += 'Нет улицы';
          4: Err += 'Нет дома';
          5: Err += 'Под вопросом. Нет квартиры. Подходит для юридических лиц или частных владений';
          6: Err += 'Адрес неполный';
          7: Err += 'Иностранный адрес';
          8: Err += 'Под вопросом.   До почтового отделения — абонентский ящик или адрес до востребования. Подходит для писем, но не для курьерской доставки.';
          9: Err += 'Под вопросом.   Нет уверенности в правильном распознавании адреса';
          10: Err += 'Под вопросом.   Дома нет в ФИАС';
        else
          Err += 'Адрес не распознан';
        end;
        if qc_complete > 0 then
          if qc_house <> 2 then
            if Err <> '' then Err = Err + ''#13#10 end;
            Err = Err + 'Дом не найден в фиас';
            if qc_geo = 0 then
              Err = Err + ' но найден на картах'
            elseif qc_geo = 1 then
              Err = Err + ' но найден похожий на картах'
            elseif qc_geo >= 2 then
              Err = Err + ' и не найден на картах';
            end;

          end;
        end;
        //AddInfoText(OBJ.FormatJSON);
      finally
        Parser.Free;
      end;
    else
      AddInfoText(IntToStr(HTTP.ResultCode) + ', ' + HTTP.ResultString);
      AddInfoText(Respons.Text);
    end;

  finally
    Arr.Free;
    HTTP.Free;
  end;
end;
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 451
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Лазарус + Synapse

Сообщение yante » 11.08.2024 13:13:38

Оба файла libeay32.dll и ssleay32.dll лежат в текущей папке...
И что интересно, что "Город" и "Остаток" - отлично читаются, а если нужно что-то отправить туда, то возвращается 200, но пустая строка...
Я думаю, если бы проблема была в этих DLL, то и Город с Остатком не читались бы...
Пойду поищу более новые DLL...

Добавлено спустя 1 час 55 минут 28 секунд:
*Rik* писал(а):
Alex2013 писал(а):Проблема ssl ? ssleay32.dll и libeay32.dll доступны ? ( и актуальных версий )

Synapse использует OpenSSL, и компилировать его (synapse) в свой проект, нужно с поддержкой конкретной версии, по умолчанию там версия 1.0, с которой уже ни куда не законнектишься, для примера у меня используется OpenSSL 1.1, под windows это будут 2 либы, можно скачать инсталлятор с официального сайта и установить всё в системный каталог, но япредпочитаю таскать либы с собой без установок:
libssl-1_1-x64.dll
libcrypto-1_1-x64.dll
По линуксом соответственно в системном каталоге библиотеки с именами по умолчнию, устанавливаются из репозитория при установке OpenSSL 1.1 штатными средствами:
libssl.so.1.1
libcrypto.so.1.1
пробовал использовать synapse с OpenSSL 3, откатился обратно, не везде поддерживается.
Для использования нужной версии в своем проекте просто добавьте в раздел uses:
Код: Выделить всё
uses httpsend, FileUtil, ftpsend, pop3send, mimemess, mimepart,
  synachar, imapsend, dpEvnthadlrs, synaser, Forms, LazUTF8,
  ssl_openssl11, ssl_openssl11_lib;

Эти файлы: ssl_openssl11, ssl_openssl11_lib поставляются с исходниками Synapse, соответственно если нужно добавить поддержку OpenSSL 3, то файлы нужно будет заменить на ssl_openssl3, ssl_openssl3_lib.

Если дело в ssl, то скорее всего вы бы не смогли сам запрос выполнить, если запрос выполняется, то дело не в ssl.

Ниже вытащил пример нормализации адреса через dadata из своего рабочего проекта c использованием Synapse, но код на Дизель-Паскале.
Код: Выделить всё
method TNormalAdres.ExecNormalDadata(Adres, Token, Key: string): Boolean;
var
  HTTP: THTTPSend;
  //SL: TStringList;
  Arr: TJSONArray;
  Parser: TJSONParser;
  OBJ: TJSONObject;
begin
  Result = False;
  Clear;

  Checked = False;
  qc_complete = -1;
  qc_house = -1;
  qc = -1;

  URL = 'https://cleaner.dadata.ru/api/v1/clean/address';
  HTTP = THTTPSend.Create;
  Arr = TJSONArray.Create;
  try
    Arr.AddStr(Adres);
    Request.Text = Arr.AsJSON;

    //AddInfoText(SL.Text);

    //AddInfoText('Отправка запроса');

    HTTP.Headers.Clear;
    HTTP.MimeType = 'application/json';
    HTTP.Headers.Add('Content-Type: application/json');
    HTTP.Headers.Add('Accept: application/json');
    HTTP.Headers.Add('Authorization: Token ' + Token);
    HTTP.Headers.Add('X-Secret: ' + Key);
    Request.SaveToStream(HTTP.Document);
    HTTP.Document.Seek(0, soBeginning);
    HTTP.HTTPMethod('POST', URL);


    if HTTP.ResultCode = 200 then
      HTTP.Document.Seek(0, soBeginning);
      Respons.LoadFromStream(HTTP.Document);
      OBJ = nil;
      Parser = TJSONParser.Create(Respons.Text);
      try
        Arr.Free;
        Arr = nil;

        Arr = Parser.Parse As TJSONArray;
        OBJ = Arr.Objects[0];
        qc_complete = OBJ.Integers['qc_complete'];
        qc_house = OBJ.Integers['qc_house'];
        qc = OBJ.Integers['qc'];
        qc_geo = OBJ.Integers['qc_geo'];

        if not OBJ.Nulls['postal_code'] then
          PIndex = OBJ.Strings['postal_code'];
        end;
        if not OBJ.Nulls['region_with_type'] then
          FRegion = OBJ.Strings['region_with_type'];
        end;
        if not OBJ.Nulls['area_with_type'] then
          FArea = OBJ.Strings['area_with_type'];
        end;
        if not OBJ.Nulls['city'] then
          FPlase = OBJ.Strings['city'] + ' ' + OBJ.Strings['city_type'];
          PlaceGuid = OBJ.Strings['city_fias_id'];
        end;
        if not OBJ.Nulls['settlement'] then
          FLocation = OBJ.Strings['settlement'] + ' ' + OBJ.Strings['settlement_type'];
          if PlaceGuid = '' then
            PlaceGuid = OBJ.Strings['settlement_fias_id'];
          end;
          if FPlase = '' then
            FPlase = FLocation;
            FLocation = '';
          end;
        end;
        if not OBJ.Nulls['street'] then
          FStreet = OBJ.Strings['street'] + ' ' + OBJ.Strings['street_type'];
        end;
        if not OBJ.Nulls['house'] then
          FHouse = OBJ.Strings['house'];
        end;
        if not OBJ.Nulls['block'] then
          FCorpus = OBJ.Strings['block'];
        end;
        if not OBJ.Nulls['flat'] then
          FRoom = OBJ.Strings['flat'];
        end;
        if not OBJ.Nulls['postal_box'] then
          AdresTypeID = 1;
          AdresType = 'PO_BOX';
          FNumAdresType = OBJ.Strings['postal_box'];
        end;
        case qc of
          1:
          begin
              Err = 'Остались лишние части';
              if not OBJ.Nulls['unparsed_parts'] then
                Err = Err + ''#13#10;
                UnparsedParts = OBJ.Strings['unparsed_parts'];
                Err = Err + UnparsedParts;
                Err = Err + ''#13#10;
              end;
          end;
          2: Err = 'Адрес пустой или заведомо мусорный или недостаточно данных для разбора';
          3: Err = 'Есть альтернативные варианты адреса';
        end;

        case qc_complete of
          0: begin
            Checked = True;
            Result = True;
          end;
          1: Err += 'Нет региона';
          2: Err += 'Нет города';
          3: Err += 'Нет улицы';
          4: Err += 'Нет дома';
          5: Err += 'Под вопросом. Нет квартиры. Подходит для юридических лиц или частных владений';
          6: Err += 'Адрес неполный';
          7: Err += 'Иностранный адрес';
          8: Err += 'Под вопросом.   До почтового отделения — абонентский ящик или адрес до востребования. Подходит для писем, но не для курьерской доставки.';
          9: Err += 'Под вопросом.   Нет уверенности в правильном распознавании адреса';
          10: Err += 'Под вопросом.   Дома нет в ФИАС';
        else
          Err += 'Адрес не распознан';
        end;
        if qc_complete > 0 then
          if qc_house <> 2 then
            if Err <> '' then Err = Err + ''#13#10 end;
            Err = Err + 'Дом не найден в фиас';
            if qc_geo = 0 then
              Err = Err + ' но найден на картах'
            elseif qc_geo = 1 then
              Err = Err + ' но найден похожий на картах'
            elseif qc_geo >= 2 then
              Err = Err + ' и не найден на картах';
            end;

          end;
        end;
        //AddInfoText(OBJ.FormatJSON);
      finally
        Parser.Free;
      end;
    else
      AddInfoText(IntToStr(HTTP.ResultCode) + ', ' + HTTP.ResultString);
      AddInfoText(Respons.Text);
    end;

  finally
    Arr.Free;
    HTTP.Free;
  end;
end;

А нет у вас возможности считать инфу по Контрагенту по ИНН?
Я чувствую, что проблема в какой-то мелочи...
И где у вас описана вот эта переменная:
Код: Выделить всё
    [b]Request[/b].SaveToStream(HTTP.Document);

В вашем коде я ее описания не нашел...
yante
незнакомец
 
Сообщения: 4
Зарегистрирован: 10.12.2020 12:54:53

Re: Лазарус + Synapse

Сообщение *Rik* » 11.08.2024 16:00:41

yante писал(а): И где у вас описана вот эта переменная:
Код: Выделить всё
    [b]Request[/b].SaveToStream(HTTP.Document);

В вашем коде я ее описания не нашел...

И Request и Response оба TStringList. Они в классе TNormalAdres объявлены, с экземпляром класса в конструкторе создаются и при его гибели в деструкторе умирают, внутрь примера не попали...
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 451
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Лазарус + Synapse

Сообщение yante » 16.08.2024 14:35:48

Товарищ мне сильно помог, дав недостающий код...
Код: Выделить всё
var
    IdHTTP1: THTTPSend;

        IdHTTP1.Headers.Add('Authorization: Token ' + Token);
        IdHTTP1.Headers.Add('Accept: ' + Accept);
        IdHTTP1.Headers.Add('Content-Type: ' + ContentType);
        IdHTTP1.Headers.Add('X-Secret: ' + SecretApi);
        IdHTTP1.Document.Write(PAnsiChar(query)^, length(query));

        IdHTTP1.HTTPMethod('POST', URL);
yante
незнакомец
 
Сообщения: 4
Зарегистрирован: 10.12.2020 12:54:53

Re: Лазарус + Synapse

Сообщение Alex2013 » 16.08.2024 17:54:00

yante писал(а):IdHTTP

Кстати почему вы в самом деле не используете библиотеку инди ? (имхо надежнее )
https://github.com/IndySockets/Indy
Alex2013
долгожитель
 
Сообщения: 3048
Зарегистрирован: 03.04.2013 11:59:44

Re: Лазарус + Synapse

Сообщение *Rik* » 16.08.2024 18:18:05

Alex2013 писал(а):
yante писал(а):IdHTTP

Кстати почему вы в самом деле не используете библиотеку инди ? (имхо надежнее )
https://github.com/IndySockets/Indy

Отпишу сюда свое имхо, почему у меня Synapse.
На счет надежности Indy можно поспорить, скорее удобнее, но точно не надежнее. Хотя может сейчас по надежности уже разницы и нет.
Когда то на Delphi я использовал Indy. Когда переехал на Lazarus, то оказалось что Indy на fpc не функционален, пришлось срочно искать замену. Попробовал Synapse и всё что мне нужно (почта, ftp, http, tcp) заработало и безупречно работает до сих пор. Обратно на Indy уже не хочется.
Ну и для погружения в Synapse очень помогает вот это: webdelphi.ru/synapse/
Аватара пользователя
*Rik*
постоялец
 
Сообщения: 451
Зарегистрирован: 19.04.2011 12:18:51
Откуда: Урал

Re: Лазарус + Synapse

Сообщение Снег Север » 17.08.2024 07:33:59

Я на делфи широко использовал и Synapse, и Indy. Последняя несколько проще и надежнее работает при редиректах сайтов. Зато если надо было сделать простое и компактное приложение, то Synapse была удобнее.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 3038
Зарегистрирован: 27.11.2007 16:14:47

Re: Лазарус + Synapse

Сообщение MaratIsk » 17.08.2024 18:38:27

использую Synapse в своем сервере приложений. перепробовал Indy, ICS и выбрал Synapse - простой, надежный, быстрый и нагрузку держит в 300+ активных подключений
MaratIsk
постоялец
 
Сообщения: 117
Зарегистрирован: 20.08.2009 18:15:20


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 17

Рейтинг@Mail.ru