获取 "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_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);
}