2016-01-28 2 views
0

Я пытаюсь получить доступ к idHTTP Delphi на json-сервере без успеха. Я пробовал все альтернативы и всегда получал ту же ошибку: «HTTP/1.1 401 Unauthorized».idHTTP.Post Ошибка HTTP/1.1 401

формат JSON для тестирования:

{"http":{"method":"POST","header":"access_token:55b3ce85b47629eeee778c0f0c9be450f1b1bc84cc377975f2d3d0d3808a4636", "content":"name=TEST&[email protected]&phone=1147001211&mobilePhone=11992329909&address=Rua+Jose+Ricardo &addressNumber=55&province=Test&notificationDisabled=True&city=Sao+Paulo&state=SP&country=Brasil&postalCode=05567210 &cpfCnpj=11111111111&personType=FISICA"}}

Url для тестирования:

http://homolog.asaas.com/api/v2/customers

Процедура тестирования:

procedure TForm4.Button2Click(Sender: TObject); 
var 
sResponse: string; 
EnvStr : TStringList; 
begin 
EnvStr := TStringList.Create; 
EnvStr.AddStrings(Memo.Lines); 
try 
    idHTTP.Request.ContentType := 'application/json'; 
    idHTTP.Request.Method:='POST'; 
    idHTTP.Request.AcceptCharSet := 'utf-8'; 
    try 
    sResponse := idHTTP.Post(EditURL.Text,EnvStr); 
    except 
    on E: Exception do 
    ShowMessage('Error on request: '#13#10 + e.Message); 
    end; 
finally 
    MemoRet.Lines.Clear; 
    MemoRet.Lines.add(sResponse); 
end; 
end; 

Тот же формат послана в PHP работает отлично, но с idHTTP возвращает ошибку: «HTTP/1.1 401 Unauthorized».

PHP работает отлично

<?php 
$api_url = "http://homolog.asaas.com/api/v2"; 
$api_key = "55b3ce85b47629eeee778c0f0c9be450f1b1bc84cc377975f2d3d0d3808a4636"; 
$url_cus = $api_url."/customers"; 
$param = array(
'name' => utf8_encode('Test'), 
'email' => '[email protected]', 
'phone' => '1147001211', 
'mobilePhone' => '11992329909', 
'address' => utf8_encode('Rua Jose Ricardo'), 
'addressNumber' => '55', 
'province' => 'Test', 
'notificationDisabled' => 'True', 
'city' => 'Sao Paulo', 
'state' =>'SP', 
'country' => 'Brasil', 
'postalCode' => '05567210', 
'cpfCnpj' => '11111111111', 
'personType' => 'FISICA' 
); 
$req = http_build_query($param); 
$ctx = stream_context_create(
array(
     "http" => array(
     "method" => "POST", 
     "header" => "access_token: $api_key", 
     "content" => $req 
     ) 
    ) 
    ); 

$res = file_get_contents($url_cus, true, $ctx); 

//PHP Object 
$obj = json_decode($res); 

//get id of register 
$id=utf8_decode("$obj->id"); 

// return result 
// return $id; 

?> 
+3

Вы можете использовать HTTP-прокси (Fiddler2, например), чтобы записать запрос на PHP POST и Delphi POST, а затем используйте инструмент diff для сравнения запросов, чтобы найти различия. – mjn

+1

Или вы можете использовать Wireshark, поскольку URL-адрес HTTP, а не HTTPS. В этом случае будет работать любой сниффер пакетов. –

+0

+1 для анализа разницы между запросами PHP и Delphi. Очевидно, что ваш код Delphi не отправляет запрос точно так же, как и работающее PHP-решение, так как если бы вы не получили этот результат. Ваш рабочий пример PHP - ваша лучшая ссылка (и публикация того, что PHP-код в вопросе сравнения может помочь другим определить вашу проблему, если вы не можете этого сделать). – Deltics

ответ

1

I am trying to access the idHTTP Delphi in a json server without success.

Вы не правильно размещения данных в формате JSON. Вы не можете использовать TStringList, так как эта версия TIdHTTP.Post() предназначена для публикации HTML-шаблонов, которые вы не публикуете. Вы должны размещать данные в формате JSON с помощью TStream вместо этого, например:

procedure TForm4.Button2Click(Sender: TObject); 
var 
sResponse: string; 
EnvStr : TStringStream; 
begin 
EnvStr := TStringStream.Create(Memo.Text, TEncoding.UTF8); 
try 
    idHTTP.Request.ContentType := 'application/json'; 
    try 
    sResponse := idHTTP.Post(EditURL.Text, EnvStr); 
    except 
    on E: Exception do 
     ShowMessage('Error on request: '#13#10 + e.Message); 
    end; 
finally 
    EnvStr.Free; 
    MemoRet.Text := sResponse; 
end; 

I've tried all the alternatives and always got the same error: "HTTP/1.1 401 Unauthorized".

Обычно это означает, что сервер запрашивает учетные данные аутентификации, которые вы не предоставляют. Однако в этой ситуации нет заголовка WWW-Authenticate, присутствующего в ответе сервера, чтобы предоставить информацию о вызове, что явно противоречит спецификации протокола HTTP.

The same format sent in PHP works perfectly

Тогда вам нужно использовать анализатор пакетов, например, Wireshark, чтобы захватить запросы HTTP, вырабатываемого PHP и TIdHTTP, а затем сравнить их для каких-либо различий, которые вы можете затем код в TIdHTTP по мере необходимости.


Update: на основе вашего PHP кода, теперь я могу видеть, что ваш код Delphi пытается POST JSON отформатированную строку, но ваш PHP код вместо POST ING в HTML веб-форму, содержащую name=value пары в application/x-www-form-urlencoded формат. В запросе не участвует JSON. Только ответ использует JSON.

Оглядываясь на это сейчас, код PHP действует на просто массивы, а не на настоящий JSON. Я думаю, вы запутались между ними, потому что представление данных массива выглядит как JSON, но на самом деле это не так. Если вы читаете документацию по PHP, http_build_query() просто возвращает строку, представляющую строку запроса url HTTP, а затем stream_context_create() создает поток на основе массива HTTP context options, где строка запроса устанавливается как опция content, а затем file_get_contents() отправляет запрос на основе этих параметров - в этом случае запрос HTTP POST с заголовком access_token и строкой запроса в качестве тела сообщения. Поскольку заголовок Content-Type не указан, по умолчанию он равен application/x-www-form-urlencoded.

Для POSTapplication/x-www-form-urlencoded запрос с TIdHTTP, вы на самом деле были на правильном пути, используя TStringList с TIdHTTP.Post(), но вы были заселять TStringList с неправильным видом данных, и вы не посылая access_token заголовок, содержащий вашу аутентификацию полномочия.

Следующий код Delphi работает, когда я проверить его:

procedure TForm4.Button2Click(Sender: TObject); 
var 
    sResponse: string; 
    EnvStr : TStringList; 
begin 
    EnvStr := TStringList.Create; 
    try 
    EnvStr.Add('name=TEST'); 
    EnvStr.Add('[email protected]'); 
    EnvStr.Add('phone=1147001211'); 
    EnvStr.Add('mobilePhone=11992329909'); 
    EnvStr.Add('address=Rua Jose Ricardo '); 
    EnvStr.Add('addressNumber=55'); 
    EnvStr.Add('province=Test'); 
    EnvStr.Add('notificationDisabled=True'); 
    EnvStr.Add('city=Sao Paulo'); 
    EnvStr.Add('state=SP'); 
    EnvStr.Add('country=Brasil'); 
    EnvStr.Add('postalCode=05567210 '); 
    EnvStr.Add('cpfCnpj=11111111111'); 
    EnvStr.Add('personType=FISICA'); 

    Http.Request.CustomHeaders.Values['access_token'] := '55b3ce85b47629eeee778c0f0c9be450f1b1bc84cc377975f2d3d0d3808a4636'; 
    try 
     sResponse := idHTTP.Post(EditURL.Text, EnvStr); 
    except 
     on E: Exception do 
     ShowMessage('Error on request: '#13#10 + e.Message); 
    end; 
    finally 
    EnvStr.Free; 
    MemoRet.Text := sResponse; 
    end; 
end; 

Ответ получен:

{"object":"customer","id":"cus_B5HmHFQSMZKD","name":"TEST","email":"[email protected]","company":null,"phone":"1147001211","mobilePhone":"11992329909","address":"Rua Jose Ricardo","addressNumber":"55","complement":null,"province":"Test","postalCode":"05567210","cpfCnpj":"11111111111","personType":"FISICA","deleted":false,"notificationDisabled":true,"city":null,"state":"null","country":"Brasil","foreignCustomer":false,"subscriptions":{"object":"list","hasMore":false,"limit":100,"offset":0,"data":[]},"payments":{"object":"list","hasMore":false,"limit":100,"offset":0,"data":[]},"notifications":{"object":"list","hasMore":false,"limit":100,"offset":0,"data":[{"object":"notification","id":"not_oZV4SlDvdjHf","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":true,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_RECEIVED","scheduleOffset":0,"deleted":false},{"object":"notification","id":"not_xNHXDZb4QHqP","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":true,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_OVERDUE","scheduleOffset":0,"deleted":false},{"object":"notification","id":"not_yt4BTyQsaRM1","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":false,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_DUEDATE_WARNING","scheduleOffset":10,"deleted":false},{"object":"notification","id":"not_LX1vanmAsBy9","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":false,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_DUEDATE_WARNING","scheduleOffset":0,"deleted":false},{"object":"notification","id":"not_AyYUHDExa5Zk","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":false,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_CREATED","scheduleOffset":0,"deleted":false},{"object":"notification","id":"not_b6NUt9qYZrM2","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":false,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"PAYMENT_UPDATED","scheduleOffset":0,"deleted":false},{"object":"notification","id":"not_Z4e4SHdXsJaA","customer":"cus_B5HmHFQSMZKD","enabled":true,"emailEnabledForProvider":false,"smsEnabledForProvider":false,"emailEnabledForCustomer":true,"smsEnabledForCustomer":true,"event":"SEND_LINHA_DIGITAVEL","scheduleOffset":0,"deleted":false}]}}

+0

Это выходит за рамки вопроса, поскольку реализация сервера не обсуждается/изменена, а как наблюдение за API RESTful и кажущееся поведение в этом случае ... «Не разрешено» было бы (* должно * быть) ** 403 ** (* Я знаю, кто вы, и вы не уполномочены делать это *). Кажется, в этом случае сервер должен возвращать плоский ** 400 Bad Request **. Но тогда слишком много API RESTful просто делают все, что им нравится, когда речь заходит о ответах и ​​HTTP-стандартах. – Deltics

+0

Согласовано. Фактически, спецификация HTTP четко заявляет, что 401 ** MUST ** включает заголовок 'WWW-Authenticate', но этот сервер этого не делает. –

+0

Я добавил пример php, который отлично работает. Я использую Fiddler (я непрофессионал) и все еще не могу найти ошибку. Если вы можете мне помочь, спасибо! – prmas