Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Русская кодировка в post idhttp


Автор: Ruless 6.4.2010, 15:50
Доброе время суток уважаемые программисты.

Столкнулся с проблемой в работе с idhttp. при попытке отправить русские символы в запросе на сервер приходит что то вроде "???? ????????"
Пробовал такой вариант.
Код

 function URLEncode(const S3: string): string;
var
  Idx: Integer;
begin
  Result := '';
  for Idx := 1 to Length(S3) do
  begin
    if S3[Idx] in ['A'..'Z', 'a'..'z', '0'..'9', '-', '=', '&', ':', '/', '?', ';', '_', '.'] then
        Result := Result + S3[Idx]
    else
      Result := Result + '%' + IntToHex(Ord(S3[Idx]), 2);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
title:='заголовок';
data9.AddFormField('title',URLEncode(title));
IdHTTP1.post('http://domen.ru/index.html',data9,M);

end;

В ответ получаю "%E7%E0%E3%EE%EB%EE%E2%EE%EA"

Подскажите как верно изменить кодировку?



Автор: Akella 6.4.2010, 20:27
Какая версия дельфи, инди - это мы должны угадывать?

Добавлено через 32 секунды
Какую кодировку нужно отправить серверу - тоже нужно отгадать?

Автор: Keeper89 6.4.2010, 20:33
Цитата(Akella @  6.4.2010,  20:27 Найти цитируемый пост)
Какая версия дельфи, инди - это мы должны угадывать?


Цитата(Akella @  6.4.2010,  20:27 Найти цитируемый пост)
Какую кодировку нужно отправить серверу - тоже нужно отгадать? 

Конечно, а ты как думал, иначе не интересно smile

Автор: Ruless 6.4.2010, 20:39
Делфи -7, Инди 10.
Кодировка на сервере вроде windows-1251.

Добавлено через 1 минуту и 23 секунды
 smile  smile)

Автор: Akella 6.4.2010, 21:29
Цитата(Ruless @  6.4.2010,  20:39 Найти цитируемый пост)
Инди 10.

Имеется ввиду последняя юникодная версия?

Автор: Ruless 6.4.2010, 22:11
да, версия юникодная . Обновлял пару недель назад.

Автор: Keeper89 7.4.2010, 00:34
А просто AnsiToUTF8 не подойдет?

Автор: Ruless 7.4.2010, 09:52

Цитата(Keeper89 @  7.4.2010,  00:34 Найти цитируемый пост)
А просто AnsiToUTF8 не подойдет? 

получил ответ такого вида " ?=B7?=B0?????=BB????????"

Автор: Ruless 7.4.2010, 15:12
При отправке через браузер и снятии данных снифером отправляется код " title=%E7%E0%E3%EE%EB%EE%E2%EE%EA" сервер понимает и выводит русские буквы.
Если отправлять через делфи и использовать функцию URLEncode сервер принимает %E7%E0%E3%EE%EB%EE%E2%EE%EA и не переводит их на русскую кодировку.. Не понимаю куда копать..

Автор: Ruless 8.4.2010, 17:15
Проблема решена. 
Ответ крылся в невозможности TIdMultiPartFormDataStream работать с перекодированными  данными.
Использование TStringList решило все проблемы. Вопрос закрыт.

Пример рабочего кода если кому интересно:

Код

 function URLEncode(const S3: string): string;
var
  Idx: Integer;
begin
  Result := '';
  for Idx := 1 to Length(S3) do
  begin
    if S3[Idx] in ['A'..'Z', 'a'..'z', '0'..'9', '-', '=', '&', ':', '/', '?', ';', '_', '.'] then
        Result := Result + S3[Idx]
    else
      Result := Result + '%' + IntToHex(Ord(S3[Idx]), 2);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
data: tstringlist;

begin
title:='Русский текст';
data:=TStringList.Create;
data.Clear;
data.Add('title='+URLEncode(title));

IdHTTP1.post('http://domen.ru/index.html',data,M);

end;

Автор: hawkins 11.4.2010, 10:47
а если бы требовались именно мультипатийный формат, то пришлось бы инди ковырять или на другую версию индей или делфи переводить прогу...

Автор: Gbukharov 15.4.2010, 05:36
У меня аналогичная проблема. Данное решение не подходит. Пишу на Delphi 2010. 
Сервер (пробую на vkontakte.ru) принимает русские буквы в виде %E0%E1%E2%E3%E4..., т.е. абвгд... т. 
д. Но из idHttp идёт post в виде%D0%B0%D0%B1%D0%B2%D0%B3%D0%B4, где 
%D0%B0 - "а", %D0%B1 - "б" и т. д. Пробовал вручную перекодировать текст, 
но в idHttp в запросе символ % упорно заменяется на символ 25.
Поясню на примере: пароль 'КатяИдеал' передается как 
%D0%9A%D0%B0%D1%82%D1%8F%D0%98%D0%B4%D0%B5%D0%B0%D0%BB, а надо 
%CA%E0%F2%FF%C8%E4%E5%E0%EB. Накатал тупую функцию 
перекодирования (не знаю, какая тут кодировка используется)
 
Код
function Convert(s:string):string;
var
  i,j: Integer;
const
  rus='АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзийклмнопрстуфхцчшщьыъэюя';
  web='%С0%C1%C2%C3%C4%C5%A8%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DC%DB%DA%DD%DE%DF%E0%E1%E2%E3%E4%E5%B8%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FC%FB%FA%FD%FE%FF';
begin
  for j := 1 to Length(s) do
  if (pos(s[j],rus)>0) then begin
    result:=result+copy(web,3*(pos(s[j],rus)-1)+1,3);
  end
  else result:=result+s[j];
end; 


В коде программы при отладке все переводится как надо 
(%CA%E0%F2%FF%C8%E4%E5%E0%EB), но на сервер всё равно уходит 
%25CA%25E0%25F2%25FF%25C8%25E4%25E5%25E0%25EB (проверял через сниффер), 
т.е все вхождения % заменяются на %25.

Кусок кода (на входе посылаются mail,pass:string):
Код
 
function ConnectAndLogin(mail,pass:string):boolean;
var
  reqs:TStringList;
  resp,s:widestring;
  temptemp:integer;
begin
  http:=TIdHTTP.Create(nil);
  http.Request.ContentType:='application/x-www-form-urlencoded';
  coom:=TIdCookieManager.Create(http);
  http.AllowCookies:=true;
  http.CookieManager:=coom;
  http.HandleRedirects:=true;
  http.ProtocolVersion:=pv1_1;
  reqs:=TStringList.Create;
  reqs.Add('email='+mail);
  reqs.Add('pass='+pass); //здесь перекодирую или нет
     {если передавать просто pass, то на сервер уйдет %D0%9A%D0%B0%D1%82%D1%8F%D0%98%D0%B4%D0%B5%D0%B0%D0%BB,
      если Convert(pass), то преобразуется всё правильно, но на сервер уйдет %25CA%25E0%25F2%25FF%25C8%25E4%25E5%25E0%25EB 
     }
  reqs.Add('expire=1');
  reqs.Add('vk=');
  resp:=http.Post('http://login.vk.com/?act=login',reqs); // в сниффере видно неверно переданные параметры
  temptemp:=pos(WideString('id=''s'''),resp)+13;
  delete(resp,1,temptemp);
  s:=copy(resp,1,pos('''',resp)-1);
  reqs.Clear;
  reqs.Add('s='+s);
  reqs.Add('op=slogin');
  reqs.Add('redirect=1');
  reqs.Add('expire=1');
  reqs.Add('to=');
  resp:=http.Post('http://vkontakte.ru/login.php?',reqs);
  reqs:=http.Response.RawHeaders;
  getcookie(reqs.Text);
//и т.д.


Если использовать Convert(pass), то HTTP Analyzer перехватывает 
в разделе PostData: 
Код

ParameterName       Value
email            somemail@yandex.ru
pass            %CA%E0%F2%FF%C8%E4%E5%E0%EB
expire            1
vk    
 - тут всё правильно, но
в RawStream: 
Код

POST /?act=login HTTP/1.0
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 88
Host: login.vk.com
Accept: text/html, */*
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

email=somemail@yandex.ru&pass=%25CA%25E0%25F2%25FF%25C8%25E4%25E5%25E0%25EB&expire=1&vk=


на что сервер отвечает:
Код

HTTP/1.1 302 Found
Server: nginx/0.7.59
Date: Thu, 15 Apr 2010 02:54:00 GMT
Content-Type: text/html; charset=windows-1251
Connection: keep-alive
X-Powered-By: PHP/5.2.6-1+lenny3
Pragma: no-cache
Cache-control: no-store
Set-Cookie: remixchk=5; expires=Tue, 12-Apr-2011 01:29:47 GMT; path=/; domain=.vkontakte.ru
P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
Location: http://vkontakte.ru/login.php?m=1&email=somemail%40yandex.ru
Vary: Accept-Encoding
Content-Length: 0

Если делать AnsiToUTF8(pass), то уходит pass=%D0%A0%D1%99%D0%A0%C2%B0%D0%A1%E2%80%9A%D0%A1%D0%8F%D0%A0%C2%98%D0%A0%D2%91%D0%A0%C2%B5%D0%A0%C2%B0%D0%A0%C2%BB&
Если  делать UTF8ToAnsi, то pass=%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD
Если описанную в посте Ruless ф-цию UrlEncode(pass), то pass=%2541A%25430%25442%2544F%25418%25434%25435%25430%2543B&
Нужно же %CA%E0%F2%FF%C8%E4%E5%E0%EB

неделю уже парюсь, кучу вариантов перепробовал с разных форумов, но ничего не помогает... Как заставить передаться верный текст?


====================================

выловил, где Delphi вставляет в код %25 - это class function TIdURI.ParamsEncode(const ASrc: string): string; модуля IdURI
но как изменить код в нём? Внёс нужные мне исправления в функцию TIdURI.ParamsEncode, но никаких изменений не произошло. Даже когда изменил константу UnsafeChars = '*#%<> []' на  UnsafeChars = '*#<> []', изменений не произошло, WatchWindow показывает старое значение '*#%<> []' smile  Модуль сохранял, перезапускал проект и весь редактор - нет эффекта  smile 

Автор: Akella 16.4.2010, 11:48
Цитата(Gbukharov @  15.4.2010,  05:36 Найти цитируемый пост)
выловил, где Delphi вставляет в код %25 - это class function TIdURI.ParamsEncode(const ASrc: string): string; модуля IdURI

это не дельфи меняет, а непосредственно компоненты инди


Цитата(Gbukharov @  15.4.2010,  05:36 Найти цитируемый пост)
но как изменить код в нём? Внёс нужные мне исправления в функцию TIdURI.ParamsEncode, но никаких изменений не произошло. Даже когда изменил константу UnsafeChars = '*#%<> []' на  UnsafeChars = '*#<> []', изменений не произошло, WatchWindow показывает старое значение '*#%<> []' smile  Модуль сохранял, перезапускал проект и весь редактор - нет эффекта  smile 

А перекомпилировал исходники инди?

И вообще. Смотрим в исходники вконтакта:
Цитата
<meta http-equiv="content-type" content="text/html; charset=windows-1251" />

Среда разработки D2010 и компоненты Indi являются юникодными. А это значит, что тебе нужно отправлять на сервер НЕ юникод, а Win1251. Я не уверен, что 
Цитата(Gbukharov @  15.4.2010,  05:36 Найти цитируемый пост)
Если  делать UTF8ToAnsi,

выполнит правильную перекодировку

Тебе нужно правильно настроить саму компоненту idHTTP, чтобы на сервер передавалось всё в кодировке win1251.
Мне так кажется. На эксперименты нет ни времени, ни желания. Но, идею, надеюсь, ты понял?

Автор: hawkins 19.4.2010, 16:06
Gbukharov, используй TStringStream для отправки данных в методе http.post. В нем можно указывать кодировку при создании -
 TStringStream.Create('строка пост параметров', 1251);

а для кодирования русских символов в строке параметров используй свой метод Convert.

Автор: iwpwork 26.3.2013, 13:21
Ищите ответы на нормальных буржуйских форумах, а не на наших, где кроме как троллить - ничего не умеют.

var
  ds: TIdMultipartFormDataStream;
begin
  ds := TIdMultipartFormDataStream.Create;
  try
    ds.AddFormField('test', UTF8Encode('äöüß'), 'utf-8').ContentTransfer := '8bit';
    try
      ShowMessage(HTTP.Post('http://localhost/test.php', ds));
    except
    end;
  finally
    FreeAndNil(ds);
  end;
end;

Автор: Akella 26.3.2013, 14:12
http://forum.vingrad.ru/index.php?showtopic=338573&view=findpost&p=2555469

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)