feat:实现统一网络请求管理系统

- 添加NetworkManager核心网络管理器
- 实现ResponseHandler统一响应处理
- 支持GET、POST、PUT、DELETE、PATCH请求类型
- 完善错误处理和超时机制
- 提供统一的信号回调接口
This commit is contained in:
2025-12-25 23:05:49 +08:00
parent 7413574672
commit 405710bdde
4 changed files with 1035 additions and 0 deletions

View File

@@ -0,0 +1,443 @@
extends Node
# 网络请求管理器 - 统一处理所有HTTP请求
# 信号定义
signal request_completed(request_id: String, success: bool, data: Dictionary)
signal request_failed(request_id: String, error_type: String, message: String)
# API配置
const API_BASE_URL = "https://whaletownend.xinghangee.icu"
const DEFAULT_TIMEOUT = 30.0
# 请求类型枚举
enum RequestType {
GET,
POST,
PUT,
DELETE,
PATCH
}
# 错误类型枚举
enum ErrorType {
NETWORK_ERROR, # 网络连接错误
TIMEOUT_ERROR, # 请求超时
PARSE_ERROR, # JSON解析错误
HTTP_ERROR, # HTTP状态码错误
BUSINESS_ERROR # 业务逻辑错误
}
# 请求状态
class RequestInfo:
var id: String
var url: String
var method: RequestType
var headers: PackedStringArray
var body: String
var timeout: float
var start_time: float
var http_request: HTTPRequest
var callback: Callable
func _init(request_id: String, request_url: String, request_method: RequestType,
request_headers: PackedStringArray = [], request_body: String = "",
request_timeout: float = DEFAULT_TIMEOUT):
id = request_id
url = request_url
method = request_method
headers = request_headers
body = request_body
timeout = request_timeout
start_time = Time.get_time_dict_from_system().hour * 3600 + Time.get_time_dict_from_system().minute * 60 + Time.get_time_dict_from_system().second
# 活动请求管理
var active_requests: Dictionary = {}
var request_counter: int = 0
func _ready():
print("NetworkManager 已初始化")
# ============ 公共API接口 ============
# 发送GET请求
func get_request(endpoint: String, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String:
return send_request(endpoint, RequestType.GET, [], "", callback, timeout)
# 发送POST请求
func post_request(endpoint: String, data: Dictionary, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String:
var body = JSON.stringify(data)
var headers = ["Content-Type: application/json"]
return send_request(endpoint, RequestType.POST, headers, body, callback, timeout)
# 发送PUT请求
func put_request(endpoint: String, data: Dictionary, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String:
var body = JSON.stringify(data)
var headers = ["Content-Type: application/json"]
return send_request(endpoint, RequestType.PUT, headers, body, callback, timeout)
# 发送DELETE请求
func delete_request(endpoint: String, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String:
return send_request(endpoint, RequestType.DELETE, [], "", callback, timeout)
# ============ 认证相关API ============
# 用户登录
func login(identifier: String, password: String, callback: Callable = Callable()) -> String:
var data = {
"identifier": identifier,
"password": password
}
return post_request("/auth/login", data, callback)
# 验证码登录
func verification_code_login(identifier: String, verification_code: String, callback: Callable = Callable()) -> String:
var data = {
"identifier": identifier,
"verification_code": verification_code
}
return post_request("/auth/verification-code-login", data, callback)
# 发送登录验证码
func send_login_verification_code(identifier: String, callback: Callable = Callable()) -> String:
var data = {"identifier": identifier}
return post_request("/auth/send-login-verification-code", data, callback)
# 用户注册
func register(username: String, password: String, nickname: String, email: String = "",
email_verification_code: String = "", callback: Callable = Callable()) -> String:
var data = {
"username": username,
"password": password,
"nickname": nickname
}
if email != "":
data["email"] = email
if email_verification_code != "":
data["email_verification_code"] = email_verification_code
return post_request("/auth/register", data, callback)
# 发送邮箱验证码
func send_email_verification(email: String, callback: Callable = Callable()) -> String:
var data = {"email": email}
return post_request("/auth/send-email-verification", data, callback)
# 验证邮箱
func verify_email(email: String, verification_code: String, callback: Callable = Callable()) -> String:
var data = {
"email": email,
"verification_code": verification_code
}
return post_request("/auth/verify-email", data, callback)
# 获取应用状态
func get_app_status(callback: Callable = Callable()) -> String:
return get_request("/", callback)
# 重新发送邮箱验证码
func resend_email_verification(email: String, callback: Callable = Callable()) -> String:
var data = {"email": email}
return post_request("/auth/resend-email-verification", data, callback)
# 忘记密码 - 发送重置验证码
func forgot_password(identifier: String, callback: Callable = Callable()) -> String:
var data = {"identifier": identifier}
return post_request("/auth/forgot-password", data, callback)
# 重置密码
func reset_password(identifier: String, verification_code: String, new_password: String, callback: Callable = Callable()) -> String:
var data = {
"identifier": identifier,
"verification_code": verification_code,
"new_password": new_password
}
return post_request("/auth/reset-password", data, callback)
# 修改密码
func change_password(user_id: String, old_password: String, new_password: String, callback: Callable = Callable()) -> String:
var data = {
"user_id": user_id,
"old_password": old_password,
"new_password": new_password
}
return put_request("/auth/change-password", data, callback)
# GitHub OAuth登录
func github_login(github_id: String, username: String, nickname: String, email: String, avatar_url: String = "", callback: Callable = Callable()) -> String:
var data = {
"github_id": github_id,
"username": username,
"nickname": nickname,
"email": email
}
if avatar_url != "":
data["avatar_url"] = avatar_url
return post_request("/auth/github", data, callback)
# ============ 核心请求处理 ============
# 发送请求的核心方法
func send_request(endpoint: String, method: RequestType, headers: PackedStringArray,
body: String, callback: Callable, timeout: float) -> String:
# 生成请求ID
request_counter += 1
var request_id = "req_" + str(request_counter)
# 构建完整URL
var full_url = API_BASE_URL + endpoint
# 创建HTTPRequest节点
var http_request = HTTPRequest.new()
add_child(http_request)
# 设置超时
http_request.timeout = timeout
# 创建请求信息
var request_info = RequestInfo.new(request_id, full_url, method, headers, body, timeout)
request_info.http_request = http_request
request_info.callback = callback
# 存储请求信息
active_requests[request_id] = request_info
# 连接信号
http_request.request_completed.connect(func(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
_on_request_completed(request_id, result, response_code, headers, body)
)
# 发送请求
var godot_method = _convert_to_godot_method(method)
var error = http_request.request(full_url, headers, godot_method, body)
print("=== 发送网络请求 ===")
print("请求ID: ", request_id)
print("URL: ", full_url)
print("方法: ", RequestType.keys()[method])
print("Headers: ", headers)
print("Body: ", body if body.length() < 200 else body.substr(0, 200) + "...")
print("发送结果: ", error)
if error != OK:
print("请求发送失败,错误代码: ", error)
_handle_request_error(request_id, ErrorType.NETWORK_ERROR, "网络请求发送失败: " + str(error))
return ""
return request_id
# 请求完成回调
func _on_request_completed(request_id: String, result: int, response_code: int,
headers: PackedStringArray, body: PackedByteArray):
print("=== 网络请求完成 ===")
print("请求ID: ", request_id)
print("结果: ", result)
print("状态码: ", response_code)
print("响应头: ", headers)
# 获取请求信息
if not active_requests.has(request_id):
print("警告: 未找到请求ID ", request_id)
return
var request_info = active_requests[request_id]
var response_text = body.get_string_from_utf8()
print("响应体长度: ", body.size(), " 字节")
print("响应内容: ", response_text if response_text.length() < 500 else response_text.substr(0, 500) + "...")
# 处理网络连接失败
if response_code == 0:
_handle_request_error(request_id, ErrorType.NETWORK_ERROR, "网络连接失败,请检查网络连接")
return
# 解析JSON响应
var json = JSON.new()
var parse_result = json.parse(response_text)
if parse_result != OK:
_handle_request_error(request_id, ErrorType.PARSE_ERROR, "服务器响应格式错误")
return
var response_data = json.data
# 处理响应
_handle_response(request_id, response_code, response_data)
# 处理响应 - 支持API v1.1.1的状态码
func _handle_response(request_id: String, response_code: int, data: Dictionary):
var request_info = active_requests[request_id]
# 检查业务成功标志
var success = data.get("success", true) # 默认true保持向后兼容
var error_code = data.get("error_code", "")
var message = data.get("message", "")
# 判断请求是否成功
var is_success = false
# HTTP成功状态码且业务成功
if (response_code >= 200 and response_code < 300) and success:
is_success = true
# 特殊情况206测试模式 - 根据API文档这是成功的测试模式响应
elif response_code == 206 and error_code == "TEST_MODE_ONLY":
is_success = true
print("🧪 测试模式响应: ", message)
# 201创建成功
elif response_code == 201:
is_success = true
if is_success:
print("✅ 请求成功: ", request_id)
# 发送成功信号
request_completed.emit(request_id, true, data)
# 调用回调函数
if request_info.callback.is_valid():
request_info.callback.call(true, data, {})
else:
print("❌ 请求失败: ", request_id, " - HTTP:", response_code, " 错误码:", error_code, " 消息:", message)
# 确定错误类型
var error_type = _determine_error_type(response_code, error_code)
# 发送失败信号
request_failed.emit(request_id, ErrorType.keys()[error_type], message)
# 调用回调函数
if request_info.callback.is_valid():
var error_info = {
"response_code": response_code,
"error_code": error_code,
"message": message,
"error_type": error_type
}
request_info.callback.call(false, data, error_info)
# 清理请求
_cleanup_request(request_id)
# 处理请求错误
func _handle_request_error(request_id: String, error_type: ErrorType, message: String):
print("❌ 请求错误: ", request_id, " - ", message)
# 发送错误信号
request_failed.emit(request_id, ErrorType.keys()[error_type], message)
# 调用回调函数
if active_requests.has(request_id):
var request_info = active_requests[request_id]
if request_info.callback.is_valid():
var error_info = {
"error_type": error_type,
"message": message
}
request_info.callback.call(false, {}, error_info)
# 清理请求
_cleanup_request(request_id)
# 确定错误类型 - 支持更多状态码
func _determine_error_type(response_code: int, error_code: String) -> ErrorType:
# 根据错误码判断
match error_code:
"SERVICE_UNAVAILABLE":
return ErrorType.BUSINESS_ERROR
"TOO_MANY_REQUESTS":
return ErrorType.BUSINESS_ERROR
"TEST_MODE_ONLY":
return ErrorType.BUSINESS_ERROR
"SEND_EMAIL_VERIFICATION_FAILED", "REGISTER_FAILED":
# 这些可能是409冲突或其他业务错误
return ErrorType.BUSINESS_ERROR
_:
# 根据HTTP状态码判断
match response_code:
409: # 资源冲突
return ErrorType.BUSINESS_ERROR
206: # 测试模式
return ErrorType.BUSINESS_ERROR
429: # 频率限制
return ErrorType.BUSINESS_ERROR
_:
if response_code >= 400 and response_code < 500:
return ErrorType.HTTP_ERROR
elif response_code >= 500:
return ErrorType.HTTP_ERROR
else:
return ErrorType.BUSINESS_ERROR
# 清理请求资源
func _cleanup_request(request_id: String):
if active_requests.has(request_id):
var request_info = active_requests[request_id]
# 移除HTTPRequest节点
if is_instance_valid(request_info.http_request):
request_info.http_request.queue_free()
# 从活动请求中移除
active_requests.erase(request_id)
print("🧹 清理请求: ", request_id)
# 转换请求方法
func _convert_to_godot_method(method: RequestType) -> HTTPClient.Method:
match method:
RequestType.GET:
return HTTPClient.METHOD_GET
RequestType.POST:
return HTTPClient.METHOD_POST
RequestType.PUT:
return HTTPClient.METHOD_PUT
RequestType.DELETE:
return HTTPClient.METHOD_DELETE
RequestType.PATCH:
return HTTPClient.METHOD_PATCH
_:
return HTTPClient.METHOD_GET
# ============ 工具方法 ============
# 取消请求
func cancel_request(request_id: String) -> bool:
if active_requests.has(request_id):
print("🚫 取消请求: ", request_id)
_cleanup_request(request_id)
return true
return false
# 取消所有请求
func cancel_all_requests():
print("🚫 取消所有请求")
var request_ids = active_requests.keys()
for request_id in request_ids:
cancel_request(request_id)
# 获取活动请求数量
func get_active_request_count() -> int:
return active_requests.size()
# 检查请求是否活动
func is_request_active(request_id: String) -> bool:
return active_requests.has(request_id)
# 获取请求信息
func get_request_info(request_id: String) -> Dictionary:
if active_requests.has(request_id):
var info = active_requests[request_id]
return {
"id": info.id,
"url": info.url,
"method": RequestType.keys()[info.method],
"start_time": info.start_time,
"timeout": info.timeout
}
return {}
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST:
# 应用关闭时取消所有请求
cancel_all_requests()