Я программирую в Delphi, и мне трудно преобразовать запрос C++ API POST в delphi. Я пытался использовать Indy, как и раньше, с предыдущими API, но этот, похоже, не работает с тем, что я пытаюсь. Может ли кто-нибудь помочь мне с этим?
Код С++, который мне нужно преобразовать:
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://sandbox.checkbook.io/v3/check/digital");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "accept: application/json");
headers = curl_slist_append(headers, "content-type: application/json");
headers = curl_slist_append(headers, "Authorization: xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxx");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\"recipient\":\"[email protected]\",\"name\":\"Widgets Inc.\",\"amount\":5,\"description\":\"Test Payment\"}");
CURLcode ret = curl_easy_perform(hnd);
Код Delphi, который у меня есть:
unit API_InvoiceCloud;
interface
uses
DB, SysUtils, System.Classes, System.JSON, IdSSLOpenSSL, VCL.Dialogs,
IdHTTP, XML.XMLIntf, xml.xmlDom, xml.XMLDoc, IDCoder, IDCoderMIME,
IdBaseComponent, IdException{, IdZLibCompressorBase{, IdCompressorZLib{,Rest.Client};
procedure CreateDigitalPayment_CheckBookAPI(mRecipientEmailAddress,
mRecipientName : String;
mPaymentAmount : Double;
mPaymentNumber,
mPaymentDescription : String);
implementation
var
{ INDY COMPONENT TO CONNECT TO API SERVER; MAKES CONNECTION }
IDHTTP1 : TidHttp;
{ SSL Connection }
SSL : TIdSSLIOHandlerSocketOpenSSL;
{ Request and Response vars }
JsonRequest, InJson : String;
JsonToSend : TStringStream; //object to store json text and pass API
JObj : TJSONObject;
Const
{ Constant variables holding the APIKEY+APISECRET and BASEURL }
nBASEURL = 'https://sandbox.checkbook.io/v3/check/digital';
nAPIKEY = 'xxxxxxxxx:xxxxxxxx';
procedure CreateDigitalPayment_CheckBookAPI(mRecipientEmailAddress,
mRecipientName : String;
mPaymentAmount : Double;
mPaymentNumber,
mPaymentDescription : String);
var
{ Response into String }
SinglePartyResponse : String;
ResponseCode : String;
{ -----------Testing---------- }
//lParamList: TStringList;
nBASEURL : String;
RequestBody : TStream;
ResponseBody : String;
begin
{ JSON body with request string }
JsonRequest := '{"recipient":"' + mRecipientEmailAddress
+ '","name":"' + mRecipientName
+ '","amount":' + FloatToStr(mPaymentAmount)
+ ',"number":"' + mPaymentNumber
+ '","description":"' + mPaymentDescription + '"}';
try
try
{ Create connection instance }
IDHTTP1 := TidHttp.Create;
{ SSL Configuration }
SSL := TIdSSLIOHandlerSocketOpenSSL.Create;
SSL.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2];
IDHTTP1.IOHandler := SSL;
{ Headers/Params }
IDHTTP1.Request.Clear;
IDHTTP1.Request.CustomHeaders.FoldLines := False;
IDHTTP1.Request.Accept := 'application/json';
IDHTTP1.Request.ContentType := 'application/json';
IDHTTP1.Request.CustomHeaders.Values['Authorization'] := nAPIKEY;
{ Saving JSON text to TStringStream Object }
JsonToSend := TStringStream.Create(JsonRequest, TEncoding.UTF8);
//JsonToSend := TStringStream.Create(JsonRequest, TEncoding.ASCII);
{ Making POST Request using INDYs TidHTTP component; Params are: URL, JsonStringObj - saving into variable }
SinglePartyResponse := IDHTTP1.Post(nBASEURL, JsonToSend);
ShowMessage(IDHTTP1.ResponseCode.ToString);
except
on E : Exception do
{ Display error message if cannot do API CALL }
begin
ShowMessage(E.ClassName+' error raised, with message : "' + E.Message + '".');
Abort;
end
end;
finally
{ Free objects from memory }
IDHTTP1.Free;
SSL.Free;
JsonToSend.Free;
end;
end;
end.
Когда я пытаюсь сделать запрос POST, я получаю ошибку 400 Bad Request. Я не уверен, что я делаю неправильно здесь.
размещено здесь: en.delphipraxis.net/topic/…
@Botje У меня нет доступа ни к одному из этих серверов, чтобы проверить это.
Отсюда и «сервер под вашим контролем». Достаточно даже вашего ноутбука.
Вам не нужен контроль над сервером. И curl, и Indy имеют опции для вывода необработанных данных HTTP, которые передаются туда и обратно. Включите эти параметры. В завитке используйте CURLOPT_VERBOSE. В Indy назначьте компонент TIdLog...
свойству TIdHTTP.Intercept
На первый взгляд, код выглядит правильно, что касается TIdHTTP
. Таким образом, наиболее вероятным виновником является то, что JSON, вероятно, искажен, то есть если в одном из текстовых значений есть символ "
. Поскольку у вас есть System.JSON
в предложении uses
, вам действительно следует использовать TJSONObject
для создания строки JSON, пусть она обрабатывает любое необходимое экранирование по мере необходимости.
@Botje Простите за невежество, я новичок в языке и API. Но спасибо, попробую. Я сделал фиктивный сервер в почтальоне и попробую то, что вы рекомендовали. Мне просто нужно выяснить, как правильно работать с этим. ХА.
@RemyLebeau Спасибо! И это то, что я понял неправильно, просто не был слишком уверен, поэтому я также попытаюсь использовать TJSONObject, как было предложено.
Найдено решение. Спасибо за предложения!
Ошибка 400 Bad Request была связана с «неверным заголовком авторизации».
Мое решение:
1. Зашел в Embarcadero, встроенный в RestDebugger, и заставил его работать там, установив BASEURL, CONTENT-TYPE, AUTHORIZATION (APIKey в Params) и CustomBody.
2. Нажал кнопку «Копировать компоненты» и вставил RESTClient
, RESTRequest
, RESTResponse
в пустую форму.
3. Создал строку JSON и передал ее в качестве параметра RESTRequest.AddBody
, а затем выполнил. (Код ниже)
RESTRequest.AddBody(JsonStringRequest, ctAPPLICATION_JSON);
RESTRequest.Execute();
RESTResponse := RESTRequest.Response;
Есть лучшие способы сделать это, но это сработало для меня.
Изменить конечные точки на сервер под вашим контролем и сравнить запросы?