Work in progress

The content of this page was not yet updated for Godot 4.1 and may be outdated. If you know how to improve this page or you can confirm that it’s up to date, feel free to open a pull request.

HTTP client class

HTTPClient provides low-level access to HTTP communication. For a higher-level interface, you may want to take a look at HTTPRequest first, which has a tutorial available here.

Warning

When exporting to Android, make sure to enable the INTERNET permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.

Here’s an example of using the HTTPClient class. It’s just a script, so it can be run by executing:

GDScriptC#

  1. c:\godot> godot -s http_test.gd
  1. c:\godot> godot -s HTTPTest.cs

It will connect and fetch a website.

GDScriptC#

  1. extends SceneTree
  2. # HTTPClient demo
  3. # This simple class can do HTTP requests; it will not block, but it needs to be polled.
  4. func _init():
  5. var err = 0
  6. var http = HTTPClient.new() # Create the Client.
  7. err = http.connect_to_host("www.php.net", 80) # Connect to host/port.
  8. assert(err == OK) # Make sure connection is OK.
  9. # Wait until resolved and connected.
  10. while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:
  11. http.poll()
  12. print("Connecting...")
  13. if not OS.has_feature("web"):
  14. OS.delay_msec(500)
  15. else:
  16. yield(Engine.get_main_loop(), "idle_frame")
  17. assert(http.get_status() == HTTPClient.STATUS_CONNECTED) # Check if the connection was made successfully.
  18. # Some headers
  19. var headers = [
  20. "User-Agent: Pirulo/1.0 (Godot)",
  21. "Accept: */*"
  22. ]
  23. err = http.request(HTTPClient.METHOD_GET, "/ChangeLog-5.php", headers) # Request a page from the site (this one was chunked..)
  24. assert(err == OK) # Make sure all is OK.
  25. while http.get_status() == HTTPClient.STATUS_REQUESTING:
  26. # Keep polling for as long as the request is being processed.
  27. http.poll()
  28. print("Requesting...")
  29. if OS.has_feature("web"):
  30. # Synchronous HTTP requests are not supported on the web,
  31. # so wait for the next main loop iteration.
  32. yield(Engine.get_main_loop(), "idle_frame")
  33. else:
  34. OS.delay_msec(500)
  35. assert(http.get_status() == HTTPClient.STATUS_BODY or http.get_status() == HTTPClient.STATUS_CONNECTED) # Make sure request finished well.
  36. print("response? ", http.has_response()) # Site might not have a response.
  37. if http.has_response():
  38. # If there is a response...
  39. headers = http.get_response_headers_as_dictionary() # Get response headers.
  40. print("code: ", http.get_response_code()) # Show response code.
  41. print("**headers:\\n", headers) # Show headers.
  42. # Getting the HTTP Body
  43. if http.is_response_chunked():
  44. # Does it use chunks?
  45. print("Response is Chunked!")
  46. else:
  47. # Or just plain Content-Length
  48. var bl = http.get_response_body_length()
  49. print("Response Length: ", bl)
  50. # This method works for both anyway
  51. var rb = PackedByteArray() # Array that will hold the data.
  52. while http.get_status() == HTTPClient.STATUS_BODY:
  53. # While there is body left to be read
  54. http.poll()
  55. # Get a chunk.
  56. var chunk = http.read_response_body_chunk()
  57. if chunk.size() == 0:
  58. if not OS.has_feature("web"):
  59. # Got nothing, wait for buffers to fill a bit.
  60. OS.delay_usec(1000)
  61. else:
  62. yield(Engine.get_main_loop(), "idle_frame")
  63. else:
  64. rb = rb + chunk # Append to read buffer.
  65. # Done!
  66. print("bytes got: ", rb.size())
  67. var text = rb.get_string_from_ascii()
  68. print("Text: ", text)
  69. quit()
  1. using Godot;
  2. public partial class HTTPTest : SceneTree
  3. {
  4. // HTTPClient demo.
  5. // This simple class can make HTTP requests; it will not block, but it needs to be polled.
  6. public override async void _Initialize()
  7. {
  8. Error err;
  9. HTTPClient http = new HTTPClient(); // Create the client.
  10. err = http.ConnectToHost("www.php.net", 80); // Connect to host/port.
  11. Debug.Assert(err == Error.Ok); // Make sure the connection is OK.
  12. // Wait until resolved and connected.
  13. while (http.GetStatus() == HTTPClient.Status.Connecting || http.GetStatus() == HTTPClient.Status.Resolving)
  14. {
  15. http.Poll();
  16. GD.Print("Connecting...");
  17. OS.DelayMsec(500);
  18. }
  19. Debug.Assert(http.GetStatus() == HTTPClient.Status.Connected); // Check if the connection was made successfully.
  20. // Some headers.
  21. string[] headers = { "User-Agent: Pirulo/1.0 (Godot)", "Accept: */*" };
  22. err = http.Request(HTTPClient.Method.Get, "/ChangeLog-5.php", headers); // Request a page from the site.
  23. Debug.Assert(err == Error.Ok); // Make sure all is OK.
  24. // Keep polling for as long as the request is being processed.
  25. while (http.GetStatus() == HTTPClient.Status.Requesting)
  26. {
  27. http.Poll();
  28. GD.Print("Requesting...");
  29. if (OS.HasFeature("web"))
  30. {
  31. // Synchronous HTTP requests are not supported on the web,
  32. // so wait for the next main loop iteration.
  33. await ToSignal(Engine.GetMainLoop(), "idle_frame");
  34. }
  35. else
  36. {
  37. OS.DelayMsec(500);
  38. }
  39. }
  40. Debug.Assert(http.GetStatus() == HTTPClient.Status.Body || http.GetStatus() == HTTPClient.Status.Connected); // Make sure the request finished well.
  41. GD.Print("Response? ", http.HasResponse()); // The site might not have a response.
  42. // If there is a response...
  43. if (http.HasResponse())
  44. {
  45. headers = http.GetResponseHeaders(); // Get response headers.
  46. GD.Print("Code: ", http.GetResponseCode()); // Show response code.
  47. GD.Print("Headers:");
  48. foreach (string header in headers)
  49. {
  50. // Show headers.
  51. GD.Print(header);
  52. }
  53. if (http.IsResponseChunked())
  54. {
  55. // Does it use chunks?
  56. GD.Print("Response is Chunked!");
  57. }
  58. else
  59. {
  60. // Or just Content-Length.
  61. GD.Print("Response Length: ", http.GetResponseBodyLength());
  62. }
  63. // This method works for both anyways.
  64. List<byte> rb = new List<byte>(); // List that will hold the data.
  65. // While there is data left to be read...
  66. while (http.GetStatus() == HTTPClient.Status.Body)
  67. {
  68. http.Poll();
  69. byte[] chunk = http.ReadResponseBodyChunk(); // Read a chunk.
  70. if (chunk.Length == 0)
  71. {
  72. // If nothing was read, wait for the buffer to fill.
  73. OS.DelayMsec(500);
  74. }
  75. else
  76. {
  77. // Append the chunk to the read buffer.
  78. rb.AddRange(chunk);
  79. }
  80. }
  81. // Done!
  82. GD.Print("Bytes Downloaded: ", rb.Count);
  83. string text = Encoding.ASCII.GetString(rb.ToArray());
  84. GD.Print(text);
  85. }
  86. Quit();
  87. }
  88. }