将C++ API POST请求转为Delphi代码时遇400错误求助
Delphi Indy POST请求返回400 Bad Request问题排查
我用Delphi开发,尝试将一段C++的API POST请求代码转换为Delphi代码,采用Indy组件,但调用接口时始终返回400 Bad Request错误。以下是原代码和我写的Delphi代码,求排查问题:
原C++代码
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\":\"testing@checkbook.io\",\"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.
排查关键点
- JSON格式不匹配:
- 原C++代码中
amount是数字类型(无引号),但Delphi代码中给amount加了双引号,变成字符串类型,API会因参数类型错误返回400。需修改为:"amount":' + FloatToStr(mPaymentAmount) + ',' - 原C++的JSON没有
number字段,Delphi代码额外添加了这个字段,API可能不识别该参数,导致请求无效,需删除"number":"' + mPaymentNumber + '",这部分。
- 原C++代码中
- 手动拼接JSON的风险:
如果参数中包含双引号、反斜杠等特殊字符,手动拼接会破坏JSON结构。建议用TJSONObject构建JSON,避免语法错误:JObj := TJSONObject.Create; try JObj.AddPair('recipient', mRecipientEmailAddress); JObj.AddPair('name', mRecipientName); JObj.AddPair('amount', TJSONNumber.Create(mPaymentAmount)); JObj.AddPair('description', mPaymentDescription); JsonRequest := JObj.ToString; finally JObj.Free; end; - Indy请求优化:
- 捕获
EIdHTTPProtocolException以获取API返回的具体错误信息(比如"invalid amount"),而不是仅捕获通用Exception:except on E: EIdHTTPProtocolException do ShowMessage('API Error: ' + E.ResponseText); on E: Exception do ShowMessage('Error: ' + E.Message); end; - 确保
TStringStream的指针在请求前指向开头:JsonToSend.Position := 0;,避免Indy发送空内容。 - 设置
IDHTTP1.Request.ContentLength := JsonToSend.Size;,让服务器明确知道请求体大小。
- 捕获
内容的提问来源于stack exchange,提问作者robhercarloz
相关产品推荐
相关产品推荐

