GDScript makes HTTP requests and session problems

Godot provides two classes, HTTPClient and HTTPRequest, for HTTP requests. Their differences are:

  • The HTTP client is the bottom layer, and needs to be returned by the server itself; HTTPRequest only needs to send a request, and the corresponding signal will be triggered when the server data is returned
  • HTTPClient does not need to be added to the node of the scene tree, while HTTPRequest inherits from the Note class and must be added to the node to function normally

Considering that I am not very familiar with the underlying things, and since I use HTTP requests, I do not need a large number of requests, so I directly use the officially encapsulated HTTPRequest class.
I wrote the first example by referring directly to the example provided by the official.
Ajax.gd

var HttpObject : HTTPRequest

#Class initialization
func _init():
	# Create an HTTP request node and connect the completion signal.
	HttpObject = HTTPRequest.new()
	HttpObject.connect("request_completed", self, "_http_request_completed")

#Execute get request
func Get(url):
	var error = HttpObject.request(url)
	if error != OK:
		push_error("HTTP An error occurred in the request.")

#Request success signal
func _http_request_completed(result, response_code, headers, body):
	if result == 0 and response_code == 200:
		#Get the complete data returned
		var response = parse_json(body.get_string_from_utf8())
		print(response)

Since I have a global singleton Global.gd, I instantiate this class directly in Global.gd:

var Ajax
var _ajaxClass = preload("res://script/network/Ajax.gd")

# First load
func _ready():
	Ajax = _ajaxClass.new()
	add_child(Ajax.HttpObject) #The node must be added before it can be used normally, otherwise an error will be reported
	
	Ajax.Get("http://127.0.0.1:8000/")

After testing, the server data can be returned normally, but then a problem is found, that is, the session saved by the server has no effect, but it is good to test it directly in the browser, which indicates that it is not a server problem.
Because the ajax classes used by js in the past were all encapsulated by others, I have a very shallow understanding of the underlying http. Later, I opened F12 in the browser to test, and found that every time the server returned a cookie in the header, and every time I made a request, I carried the cookie that was sent last time in the header.
So I modified Ajax.gd

var _cookie : String
func _init():
	_cookie = "0"
	# Create an HTTP request node and connect the completion signal.
	HttpObject = HTTPRequest.new()
	HttpObject.connect("request_completed", self, "_http_request_completed")

#Execute get request
func Get(url):
	var h = [
		"cookie: %s" % _cookie
		]
	var error = HttpObject.request(url, h)
	if error != OK:
		push_error("HTTP An error occurred in the request.")

#Request success signal
func _http_request_completed(result, response_code, headers, body):
	if result == 0 and response_code == 200:
		#Get the complete data returned
		var response = parse_json(body.get_string_from_utf8())
		print(response)
		
		#Get the cookie of the next request
		for s in headers:
			if s.left(11) == "set-cookie:":
				s = s.substr(12)
				s = s.split(";")[0]
				_cookie = s
				break

After testing, it was found that the server session was normal, and the problems such as the login account were solved. However, there was still one problem that was not solved, that is, if the last request sent was not returned, it would be ignored when sending the request.
I didn't know what a good way to do this, so I wrote a request queue myself, and then made a request when the last request had a result.
By the way, change the Get method, pass a request address and parameter list, and then assemble it.
The successful request print is also changed to signal:

#cookie information
var _cookie : String

#Request queue
var _queue = []

#Is it in the get request
var _isGeting = false

var HttpObject : HTTPRequest

#Request success signal
signal onResponse(model, body)

#Class initialization
func _init():
	_cookie = "0"
	# Create an HTTP request node and connect the completion signal.
	HttpObject = HTTPRequest.new()
	HttpObject.connect("request_completed", self, "_http_request_completed")

# Send request
func Send(model, body = {}):
	var url = "http://127.0.0.1:8000/"
	#Whether to include model
	if model != "":
		url = "%s%s" % [url, model]
	#Composition parameters
	var qy = ""
	for k in body.keys():
		if qy != "":
			qy = "%s&" % qy
		qy = "%s%s=%s" % [qy, k, body[k].http_escape()]
	if qy != "":
		url = "%s?%s" % [url, qy]
	
	_queue.append({"m" : model, "u" : url})
	_CheckSend()

# Check whether the request needs to be sent
func _CheckSend():
	if _queue.size() == 0:
		return
	
	if _isGeting:
		return
	
	_isGeting = true
	var h = [
		"cookie: %s" % _cookie
		]
	
	var url = _queue[0]["u"]
	
	print(url)
	var error = HttpObject.request(url, h)
	if error != OK:
		push_error("HTTP An error occurred in the request.")

# Request succeeded
func _http_request_completed(result, response_code, headers, body):
	if result == 0 and response_code == 200:
		#Get the complete data returned
		var response = parse_json(body.get_string_from_utf8())
		
		#Trigger event signal
		emit_signal("onResponse", _queue[0]["m"], response)
		
		#Delete successfully requested elements
		_queue.remove(0)
		
		#Get the cookie of the next request
		for s in headers:
			if s.left(11) == "set-cookie:":
				s = s.substr(12)
				s = s.split(";")[0]
				_cookie = s
				break
	else:
		push_error("Request network address %s Failed!" % _queue[0]["u"])
	
	_isGeting = false
	_CheckSend()

Calling method:
Ajax.Send("get")
Ajax.Send("register", {"user" : "nazgul", "pswd" : "123456"})

Tags: http Godot

Posted by popcornplya on Sun, 04 Sep 2022 02:15:30 +0930