• 0
Rusland

Скачать курс валют через THTTPClient

Вопросы

Пытаюсь скачать XML с курсами валют с cbr.ru. Получаю ошибку Project raised exception class EEncodingError with message 'No mapping for the Unicode character exists in the target multi-byte code page'. Как исправить?

//aUrl = http://www.cbr.ru/scripts/XML_daily.asp

function GetXML(aURL: string): String;
var
  Http: THTTPClient;
  Ss: TStringStream;
begin
  Result:='';
  Http:=THTTPClient.Create;
  try
    Ss:=TStringStream.Create('', TEncoding.UTF8);
    Http.Get(aURL,ss);
    Result:=Ss.DataString; // тут ошибка
  except    
  end;
  Http.Free;
end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 ответа на этот вопрос

  • 0

Проблема решена.

Оказалось что там кодировка Win1251, а я указал 

TStringStream.Create('', TEncoding.UTF8);

вместо

TStringStream.Create('');

И парсер на всякий случай:

uses msxml;

procedure GetKursValutAndDate(XML:String; var KDollar,KEuro:Double);
var
  XMLDoc: IXMLDOMDocument;
  Subnodes: IXMLDOMNodeList;
  AttributeNode: IXMLDOMNode;
  OperationNode: IXMLDOMNode;
  i:integer;  
begin
  KDollar:=0; KEuro:=0;
  try
    XMLDoc:=CoDOMDocument.Create;
    if Assigned(XMLDoc) and XMLDoc.loadXML(XML) then
    begin
      Subnodes:=XMLDoc.selectNodes('//ValCurs/node()');
      if Assigned(Subnodes) then
      begin
        for I := 0 to Subnodes.length - 1 do
        begin
          AttributeNode := Subnodes[I].attributes.getNamedItem('ID');
          if Assigned(AttributeNode) then
            if (AttributeNode.nodeValue='R01235') then 
            begin // доллар
              OperationNode:=Subnodes[I].selectSingleNode('.//Value');
              if Assigned(OperationNode) then
                KDollar:=StrToFloat(OperationNode.text);
            end
            else if (AttributeNode.nodeValue='R01239') then
            begin // евро
              OperationNode:=Subnodes[I].selectSingleNode('.//Value');
              if Assigned(OperationNode) then
                KEuro:=StrToFloat(OperationNode.text);
            end
        end;
      end;
    end;
  except
    Raise Exception.Create('Не удалось получить курс валют');
  end;
end;

 

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Привет.

Озадачился этой же темой но в обход XML, забираю курсы непосредственно из html. В HTML charset=utf-8 я создаю стрим как и ты в кодировке UTF-8 кидаю его в memo а русские буквы не распознаются, как быть?

Код такой:

procedure TForm2.Button1Click(Sender: TObject);
var
url:string;
Ss: TStringStream;
begin
  url:='http://www.cbr.ru/';
  Ss:=TStringStream.Create('', TEncoding.UTF8);
  NetHTTPClient1.Get(url,ss);

to_rorum.jpg.1ee882a6c2e2eaa6ada5b0b181f70bc8.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

нет такой проблемы, ваш код у меня отработал так

2017-04-19_18-47-23.png.fec011928579990685d2c690def096b8.png

 

uses
  System.Net.HTTPClient;

procedure TForm2.Button1Click(Sender: TObject);
var
  aHttp: THTTPClient;
  aStr: TStringStream;
begin
  aHttp := THTTPClient.Create;
  aStr := TStringStream.Create('', TEncoding.UTF8);
  try
    aHttp.Get('http://www.cbr.ru/', aStr);
    Memo1.text := aStr.DataString;
  finally
    aHttp.Free;
    aStr.Free;
  end;
end;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

спасибо,вы правы.

Моя проблема была в том как я передавал html в memo. я это делал так: Memo1.Lines.LoadFromStream(ss) , ваш способ, забирать из DataString проблему решил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти


  • Похожий контент

    • От kiz35196
      перевожу проект с инди на System.Net.HttpClient, никак не могу заставить его скачать файл,с инди всё как-то проще было
      подскажите пожалуйста
    • От GoldenEalge
      Подскажите как сохранить ,а потом загрузить куки в THTTPClient , как понимаю нужно работать с TCookieManager
      Сохранять пытаюсь так :
      cookies := aResponse.cookies.AsJSON(false); В cookies получаю 
      {\"Capacity\":4,\"Count\":3,\"List\":[{\"Name\":\"csrftoken\",\"Value\":\"Jljq2Sx5n9lXek4u4rri9L1zGBIExSzT\",\"Expires\":\"2019-01-06T18:41:36.854\",\"Domain\":\".i.instagram.com\",\"Path\":\"/\",\"Secure\":true,\"HttpOnly\":false},{\"Name\":\"rur\",\"Value\":\"PRN\",\"Expires\":\"1899-12-30T00:00:00.000\",\"Domain\":\".i.instagram.com\",\"Path\":\"/\",\"Secure\":false,\"HttpOnly\":false},{\"Name\":\"mid\",\"Value\":\"WlIjkQABAAF-JTqtAx_AdVdFxepj\",\"Expires\":\"2038-01-02T18:41:36.854\",\"Domain\":\".i.instagram.com\",\"Path\":\"/\",\"Secure\":false,\"HttpOnly\":false},{\"Name\":\"\",\"Value\":\"\",\"Expires\":\"1899-12-30T00:00:00.000\",\"Domain\":\"\",\"Path\":\"\",\"Secure\":false,\"HttpOnly\":false}],\"OnNotify\":null} Но как потом загрузить это обратно?
       
    • От x11
      Подскажите кросс-платформенные компоненты/библиотеки для Delphi Berlin+.
      Кроме OXML, она встроена в Delphi, но справки нет.
    • От Wovan2
      Здравствуйте.
      Немного предыстории. Нужно соорудить клиент-сервер. Клиент на Android, сервер на Windows. 
      Собственно перебираю варианты. 
      1. Сделал с помощью DataSnap. Работает. Но очень громоздко и не понятно.
      2. Tethering. Так и не смог реализовать обмен данными между сервером и клиентом типа запрос-ответ.
      3. IdTCPClient, IdTCPSever. Раньше (D7) опыт работы отрицательный, но в FMX, видимо, альтернативы нет.
      Так что сейчас предварительно реализую простой диалог запрос-ответ. Причем все вроде работает. И кода немного и быстро. НО. Уперся в кодировку. На клиенте (Android) не получается прочитать кириллицу. Сначала пробовал общаться Read, Write и передавать просто строки. Пробовал всякие индийские компоненты для кодировки. Но без понимания ничего и не получилось. В интернете где-то наткнулся на предложение передавать потоками. Реализовал. Стало лучше, но проблема с кодировкой не пропала. Скажем так, эта проблема уменьшилась вдвое. На стороне сервера все ОК. На стороне клиента либо знаки "????", либо ромбики с вопросами, либо ошибка "No mapping for the unicode character exists in the target multi-byte code page". Это я бессистемно перебирал варианты кодировок. К сожалению до сих пор так и не понимаю эти перекодировки. Вернее не так. Не понимаю откуда и куда идут какие кодировки. 
      В общем помогите пожалуйста советом или кодом. Ниже код с которым экспериментирую. (код не большой)
      Сервер
      procedure TForm1.IdTCPServerExecute(AContext: TIdContext);
      var
       s : TStringStream;
      begin
       s := TStringStream.Create;
       mem.Lines.Add(AContext.Connection.Socket.Binding.PeerIP);
       AContext.Connection.IOHandler.ReadStream(s);
       s.Position := 0;
       mem.Lines.Add(Utf8ToAnsi(s.ReadString(s.Size)));
       s.Free;
       s := TStringStream.Create;
       s.WriteString('И тебе привет');//  And You, Hi с этим все нормально, проблема только с русскими буквами
       s.Position := 0;
       AContext.Connection.IOHandler.Write(s,s.Size,true); //здесь s.Size = 13. в 26 никак не получается превратить, может быть тут что-то?
       s.Free;
      end;
      Клиент
      procedure TfrmMainClient.btn1Click(Sender: TObject);
      var s:TStringStream;
      begin
       s := TStringStream.Create;
       try
       IdTCPClient.Connect;
       if IdTCPClient.Connected
        then mem.Lines.Add('Есть контакт с сервером ' + IdTCPClient.Socket.Binding.PeerIP);
       s.WriteString('Привет');
       s.Position := 0;
        IdTCPClient.IOHandler.Write(s, s.Size, true);//здесь заметил, что s.Size = 12, похоже на unicode
        s.Clear;
        IdTCPClient.IOHandler.ReadStream(s);
        s.Position := 0;
        Mem.Lines.Add(s.ReadString(s.Size)); //ошибка здесь
       finally
        IdTCPClient.Disconnect;
        if Assigned(s)
         then s.Free;
       end;
      end;
      Этот код приводит на клиента к ошибке  "No mapping for the unicode character exists in the target multi-byte code page". На сервере сообщение "Привет" видно нормально.
      Помогите, кто чем может.
      ЗЫ. Тему "Как Получить текст по TCP (Indy) в нужной кодировке?" смотрел. Но либо она не актуальна (инди уже изменился), либо я не смог правильно понять. По крайней мере пробовал использовать это в самом начале, когда пытался передавать строки напрямую. В указанном коде IIdTextEncoding не представляю куда и как вставить.
      зы2: Извините. Пишу на Delphi 10.2. Indy 10.6.2(в комплекте с Delphi). Windows 10. Android 4 и 5
    • От Alex7wrt
      Добрый день
      В мобильном приложении используется следующая функция для чтения содержимого https страницы
      function geturlstring(url: string): string; var HTTP: THTTPClient; stream: tstringstream; begin try HTTP:=THTTPClient.Create; Stream:= TStringStream.Create('',TEncoding.UTF7); HTTP.Get(url, stream); Stream.Position:=0; Result:=stream.DataString; HTTP.Free; Stream.Free; except result:='error'; end; end; Почему-то в некоторых случаях, при подключении через WiFi, функция выдает 'error'. Хотя при проверке сам сайт с этим url открывается. Это вообще ссылка на гугловский сервис. Ошибку замечал например в WiFi сети метрополитена. Там подключение к WiFi двухэтапное - сначала открывается сервисная веб страница, нажимаешь ОК или что-то типа того, и WiFi подключается. 
      В этом случае функция выдает ошибку, хотя браузер работает, и другие и приложения типа мессенджера и вайбера видят сеть.В мобильных сетях вроде работает нормально, там ошибок не замечал.
      В чем может быть проблема? Может ли это быть потому, что url относится к https протоколу? 
       
    • От Rustam Bikeev
      Доброго времени суток уважаемые форумчане, назрел вопрос по компоненту ThttpClient. Я сам слеп в области Http что такое Post, Get  и прочие аббревиатуры для меня страшные и дикие звери которых никогда не видел. Потому и приходится спрашивать у вас. Как отправить на веб сервер запрос для получения текстового файла или картинки. Куда и как принять этот файл. Я нечерта не пойму если вы напишите сделай это сделай то, прошу вас опишите как пользоваться этими 3 функциями 
      THTTPClient.GetRequest
      THTTPClient.Post
      THTTPClient.Get
       
    • От Евгений Корепов
      Начал переносить проекты из XE8 в Berlin, столкнулся с странным затыком в простеньком коде - делаем запрос на сайт, получаем куки, делаем post авторизацию, получаем редирект, если все хорошо, то октрываем страницу из header Location. Выяснилось что не смотря на HTTPClient.AllowCookies:=True, в HTTPResponse.Cookies всегда пустота. Пришлось копать исходники. Вот что обнаружилось в source\rtl\net\System.Net.HttpClient.pas:
      procedure THTTPClient.ExecuteHTTPInternal(const ARequest: IHTTPRequest; const AContentStream: TStream; const AResponse: IHTTPResponse); var LRequest: THTTPRequest; LResponse: THTTPResponse; State: THTTPState; LExecResult: TExecutionResult; LClientCertificateList: TCertificateList; OrigSourceStreamPosition: Int64; OrigContentStreamPosition: Int64; OrigContentStreamSize: Int64; Status: Integer; LCookieHeader: string; begin LResponse := AResponse as THTTPResponse; LRequest := ARequest as THTTPRequest; OrigSourceStreamPosition := 0; if LRequest.FSourceStream <> nil then OrigSourceStreamPosition := LRequest.FSourceStream.Position; if AContentStream <> nil then begin OrigContentStreamPosition := AContentStream.Position; OrigContentStreamSize := AContentStream.Size; end else begin OrigContentStreamPosition := 0; OrigContentStreamSize := 0; end; State := Default(THTTPState); LClientCertificateList := TCertificateList.Create; try while True do begin LRequest.DoPrepare; // Add Cookies if FCookieManager <> nil then begin LCookieHeader := FCookieManager.CookieHeaders(LRequest.FURL); if LCookieHeader <> '' then LRequest.AddHeader('Cookie', LCookieHeader); // do not localize end; if not SetServerCredential(LRequest, LResponse, State) then Break; if not SetProxyCredential(LRequest, LResponse, State) then Break; if LRequest.FSourceStream <> nil then LRequest.FSourceStream.Position := OrigSourceStreamPosition; if LResponse <> nil then begin LResponse.FStream.Position := OrigContentStreamPosition; LResponse.FStream.Size := OrigContentStreamSize; end; LExecResult := DoExecuteRequest(LRequest, LResponse, AContentStream); case LExecResult of TExecutionResult.Success: begin if not SameText(LRequest.FMethodString, sHTTPMethodHead) then LResponse.DoReadData(LResponse.FStream); Status := LResponse.GetStatusCode; case Status of 200: begin Break; // Если запрос удачен, то выходим из цикла end; 401: begin State.Status := InternalState.ServerAuthRequired; end; 407: begin State.Status := InternalState.ProxyAuthRequired; end; else begin case Status of 301..304, 307: if FHandleRedirects and (LRequest.FMethodString <> sHTTPMethodHead) then begin Inc(State.Redirections); if State.Redirections > FMaxRedirects then raise ENetHTTPRequestException.CreateResFmt(@SNetHttpMaxRedirections, [FMaxRedirects]); end else Break; else end; State.Status := InternalState.Other; if DoProcessStatus(LRequest, LResponse) then Break; end; end; end; TExecutionResult.ServerCertificateInvalid: begin DoValidateServerCertificate(LRequest); end; TExecutionResult.ClientCertificateNeeded: begin DoNeedClientCertificate(LRequest, LClientCertificateList); end else raise ENetHTTPClientException.CreateRes(@SNetHttpClientUnknownError); end; if AllowCookies then UpdateCookiesFromResponse(LResponse); // Вот эта, критически важная процедура, при Status=200 никогда не выполняется end; // После выхода из цикла попадаем сюда if LRequest.FSourceStream <> nil then LRequest.FSourceStream.Seek(0, TSeekOrigin.soEnd); LResponse.FStream.Position := OrigContentStreamPosition; finally LClientCertificateList.Free; end; end; Т.е. разработчики исключили выполнение UpdateCookiesFromResponse(LResponse), которая помещает куки из ответа в HTTPClient.
      А вот код из XE8 который нормально работает с Cookies:
      function THTTPClient.ExecuteHTTPInternal(const ARequest: IHTTPRequest; const AContentStream: TStream): IHTTPResponse; var LRequest: THTTPRequest; LResponse: THTTPResponse; State: THTTPState; LExecResult: TExecutionResult; LClientCertificateList: TCertificateList; OrigSourceStreamPosition: Int64; OrigContentStreamPosition: Int64; OrigContentStreamSize: Int64; Status: Integer; LCookieHeader: string; begin Result := nil; LResponse := nil; LRequest := ARequest as THTTPRequest; OrigSourceStreamPosition := 0; if LRequest.FSourceStream <> nil then OrigSourceStreamPosition := LRequest.FSourceStream.Position; if AContentStream <> nil then begin OrigContentStreamPosition := AContentStream.Position; OrigContentStreamSize := AContentStream.Size; end else begin OrigContentStreamPosition := 0; OrigContentStreamSize := 0; end; State := Default(THTTPState); LClientCertificateList := TCertificateList.Create; try while True do begin LRequest.DoPrepare; // Add Cookies if FCookieManager <> nil then begin LCookieHeader := FCookieManager.CookieHeaders(LRequest.FURL); if LCookieHeader <> '' then LRequest.AddHeader('Cookie', LCookieHeader); // do not localize end; if not SetServerCredential(LRequest, LResponse, State) then Break; if not SetProxyCredential(LRequest, LResponse, State) then Break; if LRequest.FSourceStream <> nil then LRequest.FSourceStream.Position := OrigSourceStreamPosition; if LResponse <> nil then begin LResponse.FStream.Position := OrigContentStreamPosition; LResponse.FStream.Size := OrigContentStreamSize; end; LExecResult := DoExecuteRequest(LRequest, LResponse, AContentStream); case LExecResult of TExecutionResult.Success: begin if not SameText(LRequest.FMethodString, sHTTPMethodHead) then LResponse.DoReadData(LResponse.FStream); Status := LResponse.GetStatusCode; case Status of 200: begin Break; end; 401: begin State.Status := InternalState.ServerAuthRequired; end; 407: begin State.Status := InternalState.ProxyAuthRequired; end; else begin case Status of 301..304, 307: if FHandleRedirects and (LRequest.FMethodString <> sHTTPMethodHead) then begin Inc(State.Redirections); if State.Redirections > FMaxRedirects then raise ENetHTTPRequestException.CreateResFmt(@SNetHttpMaxRedirections, [FMaxRedirects]); end else Break; else end; State.Status := InternalState.Other; if DoProcessStatus(LRequest, LResponse) then Break; end; end; end; TExecutionResult.ServerCertificateInvalid: begin DoValidateServerCertificate(LRequest); end; TExecutionResult.ClientCertificateNeeded: begin DoNeedClientCertificate(LRequest, LClientCertificateList); end else raise ENetHTTPClientException.CreateRes(@SNetHttpClientUnknownError); end; end; if LRequest.FSourceStream <> nil then LRequest.FSourceStream.Seek(0, TSeekOrigin.soEnd); if AllowCookies then UpdateCookiesFromResponse(LResponse); // Здесь все верно, процедура за пределами цикла и выполняется всегда когда нужно. finally LClientCertificateList.Free; Result := IHTTPResponse(LResponse); end; end; А теперь вопрос: ну как так то? В продукте за 54 тысячи рублей сильно обидно исправлять такие косяки. Такое ощущение что разраб подрабатывал на стороне в проектах на php и забыл переключится на другой язык, там break прерывает работу аналога case и код работал бы правильно.
       
    • От magicxor
      При простом GET-запросе на эти URL:
      https://accounts.google.com/AddSession?hl=ru&continue=https://www.google.com/%3Fgws_rd%3Dssl
      https://accounts.google.com/Logout?hl=ru&continue=https://www.google.com/%3Fgws_rd%3Dssl&timeStmp=1463418874
      Возникает исключение:
      В инди такой проблемы нет, она отдаёт контент HTML страницы, как и положено.
      Потестить можно через C:\Users\Public\Documents\Embarcadero\Studio\18.0\Samples\Object Pascal\RTL\HttpAsyncDownload
      Это очередной баг?
      (использую Delphi 10.1 Berlin)
    • От Евгений Корепов
      Есть сайт просроченным сертификатом безопасности (госконтора, такое у них в порядке вещей), сертификат могут обновить завтра, а могут и через год, но работать с ним надо.
      Var HTTPClient: THTTPClient; HTTPResponse: IHTTPResponse; begin HTTPClient:=THTTPClient.Create; HTTPClient.OnValidateServerCertificate:=HTTPClientValidateServerCertificate; ..... try HTTPResponse:=HTTPClient.Post(FHTTPRec.Query,FHTTPRec.PostData); except on E : Exception do begin FHTTPRec.ErrorCode:=-1; FHTTPRec.ErrorMsg:=E.Message; end; ..... end; procedure THTTPThread.HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean); begin Accepted:=True; end; Под Windows код работает идеально - вызывается HTTPClientValidateServerCertificate, где принудительно доверяем сертификату.
      Под Андроид HTTPClientValidateServerCertificate или игнорируется, или до процедуры не доходит. Получаю ошибку:
      First chance exception at $A06ECCE5. Exception class EJNIException with message 'java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.'. Process tratata.apk (25487) First chance exception at $A0EA44F5. Exception class ENetHTTPCertificateException with message 'Server Certificate Invalid or not present'. Process tratata.apk (25487) Как победить проблему? 
      P.S. До этого проект работал на Indy, там подобные проблемы успешно игнорировались. Но решил перевести все на THTTPClient и вот результат :-(
       
    • От serg557
      Всем приятного времени суток-столкнулся собственно с проблемой при загрузке файла на сервер ответ выдается в кодировке ISO-8859-1, которая в программе естественно не воспринимается.
      TStringList *SL2= new TStringList; SL2->Clear(); OpenDialog1->Execute(); TIdMultiPartFormDataStream *PostFile= new TIdMultiPartFormDataStream; PostFile->Clear(); PostFile->AddFormField("FileName",ExtractFileName(OpenDialog1->FileName)); PostFile->AddFile("Filedata",OpenDialog1->FileName); PostFile->AddFormField("Upload","Submit Query"); SL2->Text=HTTP1->Post("http://...", PostFile); Memo1->Text=SL2->Text; PostFile->Free(); SL2->Free(); HTTP1->Request->ContentType="application/x-www-form-urlencoded"; Отсюда два вопроса: есть ли возможность штатными средствами перекодировать ISO-8859-1 в UTF-8, или как-то изменить кодировку 
      HTTP1->Request->ContentType="multipart/form-data; boundary= --";
      запрос веб-браузера 
      Запрос IdHTTP
      Пример ответа сервера
      Можно конечно сделать запрос на онлайн сервис - но как -то это
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу