62. HTTP Client¶
Learn how to make HTTP requests such as accessing web pages and downloading files.
62.1 URL¶
- When representing URLs in Siv3D code, using the
URL
type, which is an alias for theString
type, makes the intent clearer
# include <Siv3D.hpp>
void Main()
{
const URL url = U"https://example.com";
while (System::Update())
{
}
}
62.2 Checking Internet Connection¶
Network::IsConnected()
returns abool
indicating whether an internet connection is established
# include <Siv3D.hpp>
void Main()
{
if (Network::IsConnected())
{
Print << U"Connected";
}
else
{
Print << U"Not connected";
}
while (System::Update())
{
}
}
62.3 Opening URLs in Web Browser¶
System::LaunchBrowser(url)
opens the specified URL in a web browser- Be careful when calling this function repeatedly in the main loop, as it will open a large number of pages
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
while (System::Update())
{
if (SimpleGUI::Button(U"Visit Website", Vec2{ 40, 40 }))
{
// Open web page in browser
System::LaunchBrowser(U"https://siv3d.github.io/ja-jp/");
}
}
}
62.4 Opening Twitter Post Screen¶
Twitter::OpenTweetWindow(text)
opens a Twitter (X) post screen for posting a tweet with the specified text- Be careful when calling this function repeatedly in the main loop, as it will open a large number of pages
- Due to the nature of the Twitter API, images cannot be automatically attached, but you can copy images to the clipboard (Tutorial 65) to make it easier for users to post images
# include <Siv3D.hpp>
void PostRsultTweet(int32 score)
{
const String text = U"I got {} points in the game!\n#Siv3D\nhttps://siv3d.github.io/ja-jp/"_fmt(score);
Twitter::OpenTweetWindow(text);
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
while (System::Update())
{
if (SimpleGUI::Button(U"Share Score", Vec2{ 40, 40 }))
{
PostRsultTweet(123);
}
}
}
62.5 File Download (Synchronous)¶
- To download a file from a specified URL, the simple way is to use
SimpleHTTP::Save(url, saveFilePath)
- You can check the request result by examining the returned
HTTPResponse
. If.isOK()
istrue
, it was successful
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Siv3D logo
const URL url = U"https://raw.githubusercontent.com/Siv3D/siv3d.docs.images/master/logo/logo.png";
// Save destination file path
const FilePath saveFilePath = U"logo.png";
Texture texture;
// Download file synchronously
// If status code is 200 (OK)
if (SimpleHTTP::Save(url, saveFilePath).isOK())
{
texture = Texture{ saveFilePath };
}
else
{
Print << U"Failed";
}
while (System::Update())
{
if (texture)
{
texture.draw();
}
}
}
62.6 Response Visualization¶
- You can visualize the response status line and headers with code like this:
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Siv3D logo
const URL url = U"https://raw.githubusercontent.com/Siv3D/siv3d.docs.images/master/logo/logo.png";
// Save destination file path
const FilePath saveFilePath = U"logo.png";
if (const auto response = SimpleHTTP::Save(url, saveFilePath))
{
Console << U"------";
Console << response.getStatusLine().rtrimmed();
Console << U"status code: " << FromEnum(response.getStatusCode());
Console << U"------";
Console << response.getHeader().rtrimmed();
Console << U"------";
}
else
{
Print << U"Failed.";
}
Print << saveFilePath;
const Texture texture{ saveFilePath };
while (System::Update())
{
if (texture)
{
texture.draw();
}
}
}
62.7 File Download (Asynchronous)¶
- To avoid blocking the main thread during file download, use
SimpleHTTP::SaveAsync(url, saveFilePath)
- This function starts an asynchronous file download task and returns an
AsyncHTTPTask
type object - Query this object for task completion, and when the task is complete, examine the response
- Specifically, when
AsyncHTTPTask
's.isReady()
returnstrue
, get the response with.getResponse()
- After getting the response,
.isReady()
returnsfalse
- While the task is in progress (downloading),
.isDownloading()
returnstrue
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Siv3D logo
const URL url = U"https://raw.githubusercontent.com/Siv3D/siv3d.docs.images/master/logo/logo.png";
// Save destination file path
const FilePath saveFilePath = U"logo2.png";
Texture texture;
// Start asynchronous file download
AsyncHTTPTask task = SimpleHTTP::SaveAsync(url, saveFilePath);
while (System::Update())
{
// Asynchronous task completed
if (task.isReady())
{
// If response is 200 (OK)
if (task.getResponse().isOK())
{
texture = Texture{ saveFilePath };
}
else
{
Print << U"Failed";
}
}
// If downloading
if (task.isDownloading())
{
// Draw spinning circle
Circle{ 400, 300, 50 }.drawArc((Scene::Time() * 120_deg), 300_deg, 4, 4);
}
if (texture)
{
texture.draw();
}
}
}
62.8 File Download (Asynchronous, Progress Check, Cancel)¶
- To query download progress from an
AsyncHTTPTask
object, use.getProgress()
to get progress asHTTPProgress
type - To cancel a download task, call
.cancel()
on theAsyncHTTPTask
HTTPProgress
has the following member variables:
Code | Description |
---|---|
HTTPAsyncStatus status |
Progress status |
int64 downloaded_bytes |
Downloaded size (bytes) |
int64 uploaded_bytes |
Uploaded size (bytes) |
Optional<int64> download_total_bytes |
Total size of file to download (bytes). none if unknown |
Optional<int64> upload_total_bytes |
Total size of file to upload (bytes). none if unknown |
# include <Siv3D.hpp>
String ToString(HTTPAsyncStatus status)
{
switch (status)
{
case HTTPAsyncStatus::None_:
return U"None_";
case HTTPAsyncStatus::Downloading:
return U"Downloading";
case HTTPAsyncStatus::Failed:
return U"Failed";
case HTTPAsyncStatus::Canceled:
return U"Canceled";
case HTTPAsyncStatus::Succeeded:
return U"Succeeded";
default:
return U"Unknown";
}
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const Font font{ FontMethod::MSDF, 48, Typeface::Bold };
// Using HTTP communication test service (https://httpbin.org)
// URL that downloads 1024 bytes of data over 4 seconds
const URL url = U"https://httpbin.org/drip?duration=4&numbytes=1024&code=200&delay=0";
// Save destination file path
const FilePath saveFilePath = U"drip.txt";
AsyncHTTPTask task;
while (System::Update())
{
if (SimpleGUI::Button(U"Download", Vec2{ 20, 20 }, 140, task.isEmpty()))
{
task = SimpleHTTP::SaveAsync(url, saveFilePath);
}
if (SimpleGUI::Button(U"Cancel", Vec2{ 180, 20 }, 140, (task.getStatus() == HTTPAsyncStatus::Downloading)))
{
// Cancel the task
task.cancel();
}
// Task progress
const HTTPProgress progress = task.getProgress();
font(U"status: {}"_fmt(ToString(progress.status))).draw(24, Vec2{ 20, 60 }, ColorF{ 0.1 });
if (progress.status == HTTPAsyncStatus::Downloading)
{
// Downloaded size (bytes)
const int64 downloaded = progress.downloaded_bytes;
// File size to download (bytes). none if not available
if (const Optional<int64> total = progress.download_total_bytes)
{
font(U"downloaded: {} bytes / {} bytes"_fmt(downloaded, *total)).draw(24, Vec2{ 20, 100 }, ColorF{ 0.1 });
const double progress0_1 = (static_cast<double>(downloaded) / *total);
const RectF rect{ 20, 140, 500, 30 };
rect.drawFrame(2, 0, ColorF{ 0.1 });
RectF{ rect.pos, (rect.w * progress0_1), rect.h }.draw(ColorF{ 0.1 });
}
else
{
font(U"downloaded: {} bytes"_fmt(downloaded)).draw(24, Vec2{ 20, 100 }, ColorF{ 0.1 });
}
}
if (task.isReady())
{
if (const auto& response = task.getResponse())
{
Console << U"------";
Console << response.getStatusLine().rtrimmed();
Console << U"status code: " << FromEnum(response.getStatusCode());
Console << U"------";
Console << response.getHeader().rtrimmed();
Console << U"------";
if (response.isOK())
{
Console << FileSystem::FileSize(saveFilePath) << U" bytes";
Console << U"------";
}
}
else
{
Print << U"Failed.";
}
}
// If downloading
if (task.isDownloading())
{
// Draw spinning circle
Circle{ 400, 300, 50 }.drawArc((Scene::Time() * 120_deg), 300_deg, 4, 4);
}
}
}
62.9 GET (Synchronous)¶
- Sample GET request
# include <Siv3D.hpp>
void Main()
{
const URL url = U"https://httpbin.org/bearer";
const HashTable<String, String> headers = { { U"Authorization", U"Bearer TOKEN123456abcdef" } };
// Save destination file path
const FilePath saveFilePath = U"auth_result.json";
if (SimpleHTTP::Get(url, headers, saveFilePath).isOK())
{
const JSON json = JSON::Load(saveFilePath);
Print << U"authenticated: " << json[U"authenticated"].get<bool>();
Print << U"token: " << json[U"token"].getString();
}
else
{
Print << U"Failed";
}
while (System::Update())
{
}
}
62.10 GET (Asynchronous)¶
- Asynchronous version of GET request
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const URL url = U"https://httpbin.org/bearer";
const HashTable<String, String> headers = { { U"Authorization", U"Bearer TOKEN123456abcdef" } };
// Save destination file path
const FilePath saveFilePath = U"auth_result.json";
AsyncHTTPTask task = SimpleHTTP::GetAsync(url, headers, saveFilePath);
while (System::Update())
{
if (task.isReady())
{
if (task.getResponse().isOK())
{
const JSON json = JSON::Load(saveFilePath);
Print << U"authenticated: " << json[U"authenticated"].get<bool>();
Print << U"token: " << json[U"token"].getString();
}
else
{
Print << U"Failed.";
}
}
// If downloading
if (task.isDownloading())
{
// Draw spinning circle
Circle{ 400, 300, 50 }.drawArc((Scene::Time() * 120_deg), 300_deg, 4, 4);
}
}
}
62.11 POST (Synchronous)¶
- Sample POST request
# include <Siv3D.hpp>
void Main()
{
const URL url = U"https://httpbin.org/post";
const HashTable<String, String> headers = { { U"Content-Type", U"application/json" } };
const std::string data = JSON
{
{ U"body", U"Hello, Siv3D!" },
{ U"date", DateTime::Now().format() },
}.formatUTF8();
// Save destination file path
const FilePath saveFilePath = U"post_result.json";
if (SimpleHTTP::Post(url, headers, data.data(), data.size(), saveFilePath).isOK())
{
const JSON json = JSON::Load(saveFilePath);
Print << json.format();
}
else
{
Print << U"Failed";
}
while (System::Update())
{
}
}
62.12 POST (Asynchronous)¶
- Asynchronous version of POST request
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
const URL url = U"https://httpbin.org/post";
const HashTable<String, String> headers = { { U"Content-Type", U"application/json" } };
const std::string data = JSON
{
{ U"body", U"Hello, Siv3D!" },
{ U"date", DateTime::Now().format() },
}.formatUTF8();
// Save destination file path
const FilePath saveFilePath = U"post_result.json";
AsyncHTTPTask task = SimpleHTTP::PostAsync(url, headers, data.data(), data.size(), saveFilePath);
while (System::Update())
{
if (task.isReady())
{
if (task.getResponse().isOK())
{
const JSON json = JSON::Load(saveFilePath);
Print << json.format();
}
else
{
Print << U"Failed";
}
}
// If downloading
if (task.isDownloading())
{
// Draw spinning circle
Circle{ 400, 300, 50 }.drawArc((Scene::Time() * 120_deg), 300_deg, 4, 4);
}
}
}