获取“ EIdHTTPProtocolException,消息为'HTTP / 1.1 400 BAD REQUEST'”异常

时间:2018-08-14 10:17:28

标签: ssl twilio c++builder indy vcl

我正在开发VCL应用程序,并且必须使用其REST API集成Twilio:

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);

1 个答案:

答案 0 :(得分:0)

您发布到错误的URL。

根据Twilio的Message Resource文档,您正在发布到.../Messages,但需要发布到.../Messages.json(请注意末尾的.json

  

创建消息资源

     

POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json

     

要发送新的外发消息,请对此消息列表资源URI 进行HTTP POST。


尽管说的不是错误,但您的代码还有其他一些问题:

  • 您的Owner参数是不必要的。由于您是在同一函数中创建和销毁TIdHTTP对象,因此根本不需要为其分配Owner。并且,将那个TIdHTTP对象分配为TIdSSLIOHandlerSocketOpenSSL对象的所有者,而不是某些未知的外部所有者,会更有用。

  • 如果Message太长而无法发送,则不会向呼叫者返回错误。

  • 如果发生某些不良情况(为什么不使用C ++智能指针而不是try..finally呢?),您不能充分保护对象免于泄漏。

  • 您的catch()应该通过 const 引用捕获Exception对象。

  • 您不需要Request->Connection = "Keep-Alive",因为Post()完成后您将关闭连接,实际上您并不是在使用保持活动状态。

  • 您应该使用SSLOptions->SSLVersions属性而不是SSLOptions->Method属性。这样一来,您就可以启用sslvTLSv1_1sslvTLSv1_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);
}