TMultipartFormDataを使ってStreamをそのまま流し込んでDiscordのwebhookを叩く
副題に記述したとおり、TMultipartFormDataへ直接AddStreamします。うまく動きますでしょうか?前記事
ではいつものIndyのTIdHTTPのPOSTでTIdMultiPartFormDataStreamを使いました。このクラスにはAddStreamのメソッドがありません。他方TMultipartFormDataにはAddStreamがありますので、使ってみようというのが本記事の趣旨です。何度かやってますが、TS-WLCEからGETしたストリームを一旦ファイルに落とすことなく、そのままPOSTする感覚ですね。少なくともディスクスペースの節約にはなります。C++ Builder CEのIDEを起動して、新規のVCLプロジェクトを作ります。次図のように、

TNetHTTPClientとTNetHTTPRequestをフォームに置き、さらにTButtonx2(GetとPost)TEdit、TImage、TLabel、TMemoを配置します。次はコードです。
Unit1.hは、
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <System.Net.HttpClient.hpp>
#include <System.Net.HttpClientComponent.hpp>
#include <System.Net.URLClient.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE で管理されるコンポーネント
TButton *Post;
TButton *Get;
TImage *Image1;
TEdit *Edit1;
TLabel *Label1;
TNetHTTPClient *NetHTTPClient1;
TNetHTTPRequest *NetHTTPRequest1;
TMemo *Memo1;
void __fastcall PostClick(TObject *Sender);
void __fastcall GetClick(TObject *Sender);
void __fastcall NetHTTPClient1AuthEvent(TObject * const Sender, TAuthTargetType AnAuthTarget,
const UnicodeString ARealm, const UnicodeString AURL,
UnicodeString &AUserName, UnicodeString &APassword, bool &AbortAuth,
TAuthPersistenceType &Persistence);
void __fastcall NetHTTPRequest1RequestCompleted(TObject * const Sender, IHTTPResponse * const AResponse);
private: // ユーザー宣言
public: // ユーザー宣言
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit1.cppは、
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <System.Net.HttpClient.hpp>
#include <System.Net.HttpClientComponent.hpp>
#include <System.Net.URLClient.hpp>
#include <System.Net.Mime.hpp>
#include <Jpeg.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMemoryStream* ms = new TMemoryStream();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
NetHTTPRequest1->Client = NetHTTPClient1;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PostClick(TObject *Sender)
{
TMultipartFormData *formData = new TMultipartFormData(NULL);
// Add fields to the form data
formData->AddField("content", Edit1->Text);
formData->AddStream("file", ms,"image/jpeg","nowhere.jpg");
// Set the request method and URL
NetHTTPRequest1->MethodString = "POST";
NetHTTPRequest1->URL = "https://discord.com/api/webhooks/YourServer's ID/webhook_token";
// Send the request with the multipart form data
TMemoryStream *responseStream = new TMemoryStream();
try
{
NetHTTPRequest1->Post(NetHTTPRequest1->URL, formData, responseStream);
responseStream->Position = 0;
//Memo1.Lines.LoadFromStream(ResponseContent, Encoding);
Memo1->Lines->LoadFromStream(responseStream,TEncoding::UTF8);
} catch (const Exception &E){
ShowMessage(E.Message);
}
delete responseStream;
delete formData;
}
void __fastcall TForm1::GetClick(TObject *Sender)
{
String url = "http://192.168.0.112/snapshot.jpg";
NetHTTPRequest1->Get(url,ms);
ms->Position = 0;
//ms->SaveToFile("test.jpg");
//Image1->Picture->LoadFromFile("test.jpg");
Image1->Picture->LoadFromStream(ms);
ms->Position = 0;
//httpRequest->Disconnect();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::NetHTTPClient1AuthEvent(TObject * const Sender, TAuthTargetType AnAuthTarget,
const UnicodeString ARealm, const UnicodeString AURL,
UnicodeString &AUserName, UnicodeString &APassword, bool &AbortAuth,
TAuthPersistenceType &Persistence)
{
if (AnAuthTarget == TAuthTargetType::Server) {
AUserName = "your_id";
APassword = "your_passwd";
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::NetHTTPRequest1RequestCompleted(TObject * const Sender, IHTTPResponse * const AResponse)
{
Label1->Caption = IntToStr(AResponse->StatusCode);
}
//---------------------------------------------------------------------------
エッセンシャルなID,Token,Passwordは変えてあります。動かすと、

“Get”してから“Post”するとこんな感じです。Discord側には、

こんな感じで新着します。
TNetHTTPClientとTNetHTTPRequestの使い勝手は、TIdHTTPとはだいぶ違います。SSLのためのDLLが要らないのが長所かな。またClientとRequestの二つで一つなのも慣れないと違和感がありますかね。Debugどうするんだろうか?(お分かりの方はコメント願います。)
コメント