获取 "EIdHTTPProtocolException with message 'HTTP/1.1 400 BAD REQUEST'" 异常
Getting "EIdHTTPProtocolException with message 'HTTP/1.1 400 BAD REQUEST'" exception
我正在开发 VCL 应用程序,我必须使用其 REST 集成 Twilio API:
https://www.twilio.com/docs/usage/your-request-to-twilio
这是我的代码:
pair<bool, String> SMSTwilio::SendMessage(TComponent* Owner,
String ToNumber, String FromNumber, String Message)
{
if(Message.Length() > MESSAGE_LIMIT) {
ShowMessage("Message must have " + IntToStr(MESSAGE_LIMIT) +
" or fewer characters. Cannot send message with " +
IntToStr(Message.Length()) + "characters.");
}
AccountSID = "AC2d48*****************0deb52";
AuthToken = "9e28ec***************c0126e";
Message = "Hi";
FromNumber = "+1740****95";
ToNumber = "+9*****791";
String URI = "https://api.twilio.com/2010-04-01/Accounts/"
+ AccountSID +
"/Messages";
TStringList* params = new TStringList();
params->Add("From=" + FromNumber);
params->Add("To=" + ToNumber);
params->Add("Body=" + Message);
TIdHTTP* HTTP = new TIdHTTP(Owner);
HTTP->Request->Connection = "Keep-Alive";
HTTP->Request->ContentType = "application/x-www-form-urlencoded";
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(Owner);
Handler->SSLOptions->Method = sslvTLSv1;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result = "";
__try {
try {
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
Result = HTTP->Post(URI, params);
isSuccess = true;
} catch(Exception &e) {
isSuccess = false;
Result = e.Message;
}
}
__finally {
delete HTTP;
delete params;
}
return make_pair(isSuccess, Result);
}
我收到 EIdHTTPProtocolException
消息 "HTTP/1.1 400 BAD REQUEST"
由 Result = HTTP->Post(URI, params);
抛出。
你 post 打错了 URL。
你正在 post 到 .../Messages
但你需要 post 到 .../Messages.json
(注意最后的 .json
),根据 Twilio 的Message Resource 文档:
Create a Message resource
POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
To send a new outgoing message, make an HTTP POST to this Messages list resource URI.
此外,虽然不是说错误,但您的代码还有一些其他问题:
您的 Owner
参数是不必要的。由于您是在同一个函数中创建和销毁 TIdHTTP
对象,因此根本不需要为它分配 Owner
。将 TIdHTTP
对象指定为 TIdSSLIOHandlerSocketOpenSSL
对象的所有者而不是某个未知的外部所有者会更有用。
如果 Message
太长而无法发送,您不会向调用方返回错误。
如果发生不好的事情,你没有充分保护你的对象免受泄漏(为什么不使用 C++ 智能指针而不是 try..finally
?)。
您的 catch()
应该通过 const 引用捕获 Exception
对象。
您不需要 Request->Connection = "Keep-Alive"
因为您在 Post()
完成后关闭连接,您实际上并没有使用 keep-alive。
您应该使用 SSLOptions->SSLVersions
属性 而不是 SSLOptions->Method
属性。这将允许您启用 sslvTLSv1_1
和 sslvTLSv1_2
,因为现在许多服务器正在逐步淘汰 TLS 1.0,因此您应该尽快做好准备。
话虽如此,试试这样的东西:
#include <utility>
#include <memory>
std::pair<bool, String> SMSTwilio::SendMessage(
String ToNumber, String FromNumber, String Message)
{
if (Message.Length() > MESSAGE_LIMIT) {
String msg = Format(_D("Message must have %d or fewer characters. Cannot send message with %d characters."), ARRAYOFCONST(( MESSAGE_LIMIT, Message.Length() )) );
//ShowMessage(msg);
return std::make_pair(false, msg);
}
String AccountSID = _D("AC2d48*****************0deb52");
String AuthToken = _D("9e28ec***************c0126e");
//Message = _D("Hi");
//FromNumber = _D("+1740****95");
//ToNumber = _D("+9*****791");
String URI = Format(_D("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"), ARRAYOFCONST(( AccountSID )) );
std::unique_ptr<TStringList> params(new TStringList); // or std::auto_ptr prior to C++11
params->Add(_D("From=") + FromNumber);
params->Add(_D("To=") + ToNumber);
params->Add(_D("Body=") + Message);
std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP(nullptr)); // or std::auto_ptr prior to C++11
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
//HTTP->Request->Connection = _D("Keep-Alive");
HTTP->Request->ContentType = _D("application/x-www-form-urlencoded");
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(HTTP.get());
Handler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvTLSv1 << sslvTLSv1_1 << sslvTLSv1_2;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result;
try {
Result = HTTP->Post(URI, params);
isSuccess = true;
}
catch (const Exception &e) {
isSuccess = false;
Result = e.Message;
}
return std::make_pair(isSuccess, Result);
}
我正在开发 VCL 应用程序,我必须使用其 REST 集成 Twilio API:
https://www.twilio.com/docs/usage/your-request-to-twilio
这是我的代码:
pair<bool, String> SMSTwilio::SendMessage(TComponent* Owner,
String ToNumber, String FromNumber, String Message)
{
if(Message.Length() > MESSAGE_LIMIT) {
ShowMessage("Message must have " + IntToStr(MESSAGE_LIMIT) +
" or fewer characters. Cannot send message with " +
IntToStr(Message.Length()) + "characters.");
}
AccountSID = "AC2d48*****************0deb52";
AuthToken = "9e28ec***************c0126e";
Message = "Hi";
FromNumber = "+1740****95";
ToNumber = "+9*****791";
String URI = "https://api.twilio.com/2010-04-01/Accounts/"
+ AccountSID +
"/Messages";
TStringList* params = new TStringList();
params->Add("From=" + FromNumber);
params->Add("To=" + ToNumber);
params->Add("Body=" + Message);
TIdHTTP* HTTP = new TIdHTTP(Owner);
HTTP->Request->Connection = "Keep-Alive";
HTTP->Request->ContentType = "application/x-www-form-urlencoded";
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(Owner);
Handler->SSLOptions->Method = sslvTLSv1;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result = "";
__try {
try {
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
Result = HTTP->Post(URI, params);
isSuccess = true;
} catch(Exception &e) {
isSuccess = false;
Result = e.Message;
}
}
__finally {
delete HTTP;
delete params;
}
return make_pair(isSuccess, Result);
}
我收到 EIdHTTPProtocolException
消息 "HTTP/1.1 400 BAD REQUEST"
由 Result = HTTP->Post(URI, params);
抛出。
你 post 打错了 URL。
你正在 post 到 .../Messages
但你需要 post 到 .../Messages.json
(注意最后的 .json
),根据 Twilio 的Message Resource 文档:
Create a Message resource
POST
https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
To send a new outgoing message, make an HTTP POST to this Messages list resource URI.
此外,虽然不是说错误,但您的代码还有一些其他问题:
您的
Owner
参数是不必要的。由于您是在同一个函数中创建和销毁TIdHTTP
对象,因此根本不需要为它分配Owner
。将TIdHTTP
对象指定为TIdSSLIOHandlerSocketOpenSSL
对象的所有者而不是某个未知的外部所有者会更有用。如果
Message
太长而无法发送,您不会向调用方返回错误。如果发生不好的事情,你没有充分保护你的对象免受泄漏(为什么不使用 C++ 智能指针而不是
try..finally
?)。您的
catch()
应该通过 const 引用捕获Exception
对象。您不需要
Request->Connection = "Keep-Alive"
因为您在Post()
完成后关闭连接,您实际上并没有使用 keep-alive。您应该使用
SSLOptions->SSLVersions
属性 而不是SSLOptions->Method
属性。这将允许您启用sslvTLSv1_1
和sslvTLSv1_2
,因为现在许多服务器正在逐步淘汰 TLS 1.0,因此您应该尽快做好准备。
话虽如此,试试这样的东西:
#include <utility>
#include <memory>
std::pair<bool, String> SMSTwilio::SendMessage(
String ToNumber, String FromNumber, String Message)
{
if (Message.Length() > MESSAGE_LIMIT) {
String msg = Format(_D("Message must have %d or fewer characters. Cannot send message with %d characters."), ARRAYOFCONST(( MESSAGE_LIMIT, Message.Length() )) );
//ShowMessage(msg);
return std::make_pair(false, msg);
}
String AccountSID = _D("AC2d48*****************0deb52");
String AuthToken = _D("9e28ec***************c0126e");
//Message = _D("Hi");
//FromNumber = _D("+1740****95");
//ToNumber = _D("+9*****791");
String URI = Format(_D("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"), ARRAYOFCONST(( AccountSID )) );
std::unique_ptr<TStringList> params(new TStringList); // or std::auto_ptr prior to C++11
params->Add(_D("From=") + FromNumber);
params->Add(_D("To=") + ToNumber);
params->Add(_D("Body=") + Message);
std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP(nullptr)); // or std::auto_ptr prior to C++11
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
//HTTP->Request->Connection = _D("Keep-Alive");
HTTP->Request->ContentType = _D("application/x-www-form-urlencoded");
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(HTTP.get());
Handler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvTLSv1 << sslvTLSv1_1 << sslvTLSv1_2;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result;
try {
Result = HTTP->Post(URI, params);
isSuccess = true;
}
catch (const Exception &e) {
isSuccess = false;
Result = e.Message;
}
return std::make_pair(isSuccess, Result);
}