Open WangShuXian6 opened 8 months ago
配置插件 Request
Source/Ro2ea/Ro2ea.Build.cs
PublicDependencyModuleNames.AddRange(new string[]
{
"Request"
});
直接导入 根public的头文件即可,省略public路径
例如:
导入 Plugins/Request/Source/Request/Public/Request.h
#include "Request.h"
以Request插件为例。 官方只提供了蓝图文档,根public目录没有导出有用的头文件,实际头文件均在根Private目录下。
必须将插件安装到项目的 Plugins
目录下,
如果安装在引擎目录下无法导入非根public的头文件
E:\Unreal Projects 532\Ro2ea\Plugins\Request
然后重新生成项目
这将自动在 Ro2ea.uproject 的"Plugins" 加入
Source/Ro2ea/Ro2ea.Build.cs
使用 PublicDependencyModuleNames.AddRange 导入插件 Request
Source/Ro2ea/Ro2ea.Build.cs
使用 PublicIncludePaths.AddRange 导入要使用的插件目录。
"Request/Private" 表示 插件的 目录 Plugins/Request/Source/Request/Private
Source/Ro2ea/Ro2ea.Build.cs
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Ro2ea : ModuleRules
{
public Ro2ea(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PrivateDependencyModuleNames.AddRange(
new string[]
{
"GameplayMessageRuntime"
}
);
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "GameplayAbilities", "GameplayTags",
"GameplayTasks", "NavigationSystem", "NavigationSystem", "Niagara", "AIModule","Request"
});
PublicIncludePaths.AddRange(new string[] { "Request/Public","Request/Private"});
}
}
关键代码
PublicDependencyModuleNames.AddRange(new string[]
{
"Request"
});
PublicIncludePaths.AddRange(new string[] { "Request/Public","Request/Private"});
#include"Request/Private/Handler/RequestHandler.h"
这代表导入了 Plugins/Request/Source/Request/Private/Handler/RequestHandler.h
注意:FJsonObjectConverter::UStructToJsonObjectString 会将结构体的首字母转为小写,用以符合JSON规范,这是虚幻内置行为。后端服务通用的参数验证会导致请求返回400响应。
FJsonObjectConverter::UStructToJsonObjectString
FJsonObjectConverter::JsonObjectStringToUStruct
Source/Ro2ea/Ro2ea.Build.cs
PublicDependencyModuleNames.AddRange(new string[]
{
"Json", "JsonUtilities"
});
#include "JsonObjectConverter.h"
USTRUCT(BlueprintType)
struct FPlayerData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
};
void ARoCharacter::BeginPlay()
{
Super::BeginPlay();
// 结构体转换为json字符串
FPlayerData PlayerData;
PlayerData.Name = FString("PlayerOne");
FString Content;
FJsonObjectConverter::UStructToJsonObjectString(FPlayerData::StaticStruct(), &PlayerData, Content, 0, 0);
UE_LOG(LogTemp, Warning, TEXT("结构体转换为json字符串: %s"), *Content);
// json字符串转换为结构体
FString JsonString = TEXT("{\"Name\":\"PlayerOne2222\"}");
FPlayerData PlayerData2;
if (FJsonObjectConverter::JsonObjectStringToUStruct<FPlayerData>(JsonString, &PlayerData2, 0, 0))
{
// 转换成功,PlayerData 现在被填充了 JSON 字符串中的数据
UE_LOG(LogTemp, Warning, TEXT("json字符串转换为结构体: %s"), *PlayerData2.Name);
}
else
{
// 处理转换失败的情况
UE_LOG(LogTemp, Warning, TEXT("json字符串转换为结构体失败"));
}
}
Source/Ro2ea/Public/User/Util/RoJson.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "JsonObjectConverter.h"
#include "RoJson.generated.h"
UCLASS()
class RO2EA_API URoJson : public UObject
{
GENERATED_BODY()
public:
// 将 UStruct 转换为 JSON 字符串
template <typename StructType>
static bool UStructToJSONString(const StructType& InStruct, FString& OutJsonString)
{
return FJsonObjectConverter::UStructToJsonObjectString(StructType::StaticStruct(), &InStruct, OutJsonString, 0,
0, 0, nullptr, true);
}
// 将 JSON 字符串转换为 UStruct
template <typename StructType>
static bool JSONStringToUStruct(const FString& InJsonString, StructType& OutStruct)
{
return FJsonObjectConverter::JsonObjectStringToUStruct<StructType>(InJsonString, &OutStruct, 0, 0, false);
}
// 数组
template <typename StructType>
static bool UStructArrayToJSONString(const TArray<StructType>& InStructArray, FString& OutJsonString)
{
TArray<FString> JsonStrings;
for (const StructType& Item : InStructArray)
{
FString ItemJsonString;
if (!FJsonObjectConverter::UStructToJsonObjectString(StructType::StaticStruct(), &Item, ItemJsonString, 0,
0, 0, nullptr, true))
{
return false; // 转换失败,直接返回
}
JsonStrings.Add(ItemJsonString);
}
OutJsonString = FString::Printf(TEXT("[%s]"), *FString::Join(JsonStrings, TEXT(",")));
return true;
}
template <typename StructType>
static bool JSONStringToUStructArray(const FString& InJsonString, TArray<StructType>& OutStructArray)
{
if (!InJsonString.StartsWith("[") || !InJsonString.EndsWith("]"))
{
return false; // 不是有效的JSON数组格式
}
return FJsonObjectConverter::JsonArrayStringToUStruct<StructType>(InJsonString, &OutStructArray, 0, 0, false);
}
};
Source/Ro2ea/Private/User/Util/RoJson.cpp
#include "User/Util/RoJson.h"
USTRUCT(BlueprintType)
struct FPlayerData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
};
void ARoCharacter::BeginPlay()
{
Super::BeginPlay();
// 结构体转换为json字符串
FPlayerData PlayerData0;
PlayerData0.Name = TEXT("PlayerOne000");
FString JsonString0;
URoJson::UStructToJSONString(PlayerData0, JsonString0);
// json字符串转换为结构体
FPlayerData NewPlayerData0;
URoJson::JSONStringToUStruct(JsonString0, NewPlayerData0);
}
依赖 UE结构体和JSON字符串互转工具函数类 URoJson
注意:测试时,需要关闭代理软件,否则由于代理和模拟服务都使用了127.0.0.1,虚幻引擎无法触达本地模拟服务端,会导致503响应。
Source/Ro2ea/Ro2ea.Build.cs
PublicDependencyModuleNames.AddRange(new string[]
{
"Json", "JsonUtilities", "Http"
});
src\auth\users.controller.ts
@Controller('users')
export class UsersController {
constructor(
private readonly authService: AuthService,
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}
@Post('test')
async createTest(@Body() body) {
console.log(`测试::${JSON.stringify(body)}`);
return { dat: body, ResponseMessage: 666 };
}
}
Source/Ro2ea/Public/User/Http/RoHttpZ.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "RoHttpZ.generated.h"
DECLARE_DELEGATE_TwoParams(FOnHttpRequestCompleted, FHttpResponsePtr /*Response*/, bool /*bWasSuccessful*/);
UCLASS()
class RO2EA_API URoHttpZ : public UObject
{
GENERATED_BODY()
public:
static void HttpRequestPost(const FString& Url, const FString& Content, const FOnHttpRequestCompleted& Callback)
{
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->OnProcessRequestComplete().BindLambda(
[Callback](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
Callback.ExecuteIfBound(Response, bWasSuccessful);
});
HttpRequest->SetURL(Url);
HttpRequest->SetVerb(TEXT("POST"));
HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json"));
HttpRequest->SetContentAsString(Content);
HttpRequest->ProcessRequest();
}
};
Source/Ro2ea/Private/User/Http/RoHttpZ.cpp
#include "User/Http/RoHttpZ.h"
Source/Ro2ea/Public/User/Http/Headers.h
#pragma once
#include "CoreMinimal.h"
#include "Interfaces/IHttpRequest.h"
#include "UObject/Object.h"
#include "Headers.generated.h"
USTRUCT(BlueprintType)
struct FHttpHeaders
{
GENERATED_BODY()
TMap<FString, FString> HeaderMap;
// 构造函数,用于初始化默认值
FHttpHeaders()
{
// 设置默认的Content-Type
SetHeader(TEXT("Content-Type"), TEXT("application/json"));
}
// 动态设置或更新头部信息的方法
void SetHeader(const FString& Key, const FString& Value)
{
HeaderMap.Add(Key, Value);
}
// 应用所有请求头到HTTP请求的方法
void ApplyToRequest(TSharedRef<IHttpRequest, ESPMode::ThreadSafe>& HttpRequest) const
{
for (const auto& Header : HeaderMap)
{
HttpRequest->SetHeader(Header.Key, Header.Value);
}
}
};
Source/Ro2ea/Private/User/Http/Headers.cpp
#include "User/Http/Headers.h"
Source/Ro2ea/Public/User/Http/RoHttp.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "Headers.h"
#include "RoHttp.generated.h"
UENUM(BlueprintType)
enum class EHttpRequestMethod : uint8
{
GET UMETA(DisplayName = "GET"),
POST UMETA(DisplayName = "POST"),
PUT UMETA(DisplayName = "PUT"),
DELETE UMETA(DisplayName = "DELETE"),
PATCH UMETA(DisplayName = "PATCH"),
};
USTRUCT(BlueprintType)
struct FHttpResponseData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 StatusCode;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Content;
// 根据需要添加更多的响应字段
};
UCLASS()
class RO2EA_API URoHttp : public UObject
{
GENERATED_BODY()
public:
using FOnResponseReceived = TDelegate<void(const FHttpResponseData&)>;
static void HttpRequest(const FString& Url, const EHttpRequestMethod RequestMethod, const FHttpHeaders& Headers,
const FString& RequestBody,
const FOnResponseReceived& OnResponse)
{
TMap<EHttpRequestMethod, FString> RequestMethodMap;
RequestMethodMap.Add(EHttpRequestMethod::GET, TEXT("GET"));
RequestMethodMap.Add(EHttpRequestMethod::POST, TEXT("POST"));
RequestMethodMap.Add(EHttpRequestMethod::PUT, TEXT("PUT"));
RequestMethodMap.Add(EHttpRequestMethod::DELETE, TEXT("DELETE"));
RequestMethodMap.Add(EHttpRequestMethod::PATCH, TEXT("PATCH"));
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HttpRequest = FHttpModule::Get().CreateRequest();
// 设置请求头
Headers.ApplyToRequest(HttpRequest);
// 确保映射中包含了请求方法
if (RequestMethodMap.Contains(RequestMethod))
{
HttpRequest->SetVerb(RequestMethodMap[RequestMethod]);
}
else
{
// 如果未找到相应的请求方法,可以使用默认方法或返回错误
// 使用GET作为默认方法或添加错误处理
HttpRequest->SetVerb(TEXT("GET"));
}
HttpRequest->SetURL(Url);
HttpRequest->SetContentAsString(RequestBody);
// 处理响应
HttpRequest->OnProcessRequestComplete().BindLambda(
[OnResponse](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
FHttpResponseData ResponseData;
if (bWasSuccessful && Response.IsValid())
{
ResponseData.StatusCode = Response->GetResponseCode();
ResponseData.Content = Response->GetContentAsString();
}
else
{
// 处理错误情况
ResponseData.StatusCode = -1;
ResponseData.Content = TEXT("Failed to get a valid response.");
}
if (OnResponse.IsBound())
{
OnResponse.Execute(ResponseData);
}
});
// 发送请求
HttpRequest->ProcessRequest();
}
};
Source/Ro2ea/Private/User/Http/RoHttp.cpp
#include "User/Http/RoHttp.h"
Source/Ro2ea/Public/User/Http/RoHttpStruct.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "User/Http/RoHttp.h"
#include "User/Util/RoJson.h"
#include "RoHttpStruct.generated.h"
UCLASS()
class RO2EA_API URoHttpStruct : public UObject
{
GENERATED_BODY()
public:
using FOnResponseReceivedStruct = TDelegate<void(const FHttpResponseData&)>;
// 新增方法,处理结构体请求和响应
template <typename RequestStructType, typename ResponseStructType>
static void HttpRequestWithStruct(const FString& Url, const EHttpRequestMethod RequestMethod,
const FHttpHeaders& Headers,
const RequestStructType& RequestData,
const TDelegate<void(const ResponseStructType&, bool bWasSuccessful)>& OnResponse)
{
FString RequestBody;
URoJson::UStructToJSONString(RequestData, RequestBody);
// 创建符合 URoHttp::HttpRequest 需求的委托
URoHttp::FOnResponseReceived HttpResponseDelegate = URoHttp::FOnResponseReceived::CreateLambda(
[OnResponse](const FHttpResponseData& HttpResponseData)
{
ResponseStructType ResponseData;
// 确定这里应该是 HttpResponseData 本身提供的成功标志,或你基于状态码自定义的成功逻辑
bool bSuccess = HttpResponseData.StatusCode >= 200 && HttpResponseData.StatusCode < 300 &&
URoJson::JSONStringToUStruct<ResponseStructType>(HttpResponseData.Content, ResponseData);
// 调用原始委托,这里 bSuccess 变量用于表示是否成功
OnResponse.ExecuteIfBound(ResponseData, bSuccess);
});
URoHttp::HttpRequest(Url, RequestMethod, Headers, RequestBody, HttpResponseDelegate);
}
};
Source/Ro2ea/Private/User/Http/RoHttpStruct.cpp
#include "User/Http/RoHttpStruct.h"
Source/Ro2ea/Public/User/Http/RoHttpManager.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "Headers.h"
#include "RoHttpManager.generated.h"
UCLASS()
class RO2EA_API URoHttpManager : public UObject
{
GENERATED_BODY()
private:
static FString AccessToken;
public:
// 设置token
static void SetAccessToken(const FString& Token)
{
AccessToken = Token;
}
// 获取当前的token
static FString GetAccessToken()
{
return AccessToken;
}
// 应用通用请求头
static void ApplyGlobalHeaders(FHttpHeaders& Headers)
{
if (!AccessToken.IsEmpty())
{
Headers.SetHeader(TEXT("Authorization"), FString::Printf(TEXT("Bearer %s"), *AccessToken));
}
}
};
Source/Ro2ea/Private/User/Http/RoHttpManager.cpp
#include "User/Http/RoHttpManager.h"
// 按照C++的规则,即使是静态成员,也需要在某个地方定义它,以便为它分配存储空间。
// 初始化静态成员变量
FString URoHttpManager::AccessToken = "";
Source/Ro2ea/Public/User/Http/RoHttpService.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "RoHttpStruct.h"
#include "RoHttp.h"
#include "RoHttpManager.h"
#include "RoHttpService.generated.h"
UCLASS()
class RO2EA_API URoHttpService : public UObject
{
GENERATED_BODY()
public:
using FOnResponseReceived = TDelegate<void(const FHttpResponseData&)>;
using FOnResponseArrayReceived = TDelegate<void(const FHttpResponseData&)>;
template <typename ResponseStructType, typename ErrorResponseType>
static FOnResponseReceived CreateResponseDelegate(
const TFunction<void(const ResponseStructType&, bool)>& SuccessFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc)
{
return FOnResponseReceived::CreateLambda(
[SuccessFunc, ErrorFunc](const FHttpResponseData& HttpResponseData)
{
if (HttpResponseData.StatusCode >= 200 && HttpResponseData.StatusCode < 300)
{
ResponseStructType ResponseData;
bool bSuccess = URoJson::JSONStringToUStruct<ResponseStructType>(
HttpResponseData.Content, ResponseData);
UE_LOG(LogTemp, Warning, TEXT("响应 StatusCode: %d"), HttpResponseData.StatusCode);
UE_LOG(LogTemp, Warning, TEXT("响应 HttpResponseData.Content: %s"), *HttpResponseData.Content);
if (bSuccess || HttpResponseData.StatusCode == 204)
{
SuccessFunc(ResponseData, true);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to parse success response."));
}
}
else
{
ErrorResponseType ErrorData;
bool bErrorParsed = URoJson::JSONStringToUStruct<ErrorResponseType>(
HttpResponseData.Content, ErrorData);
if (bErrorParsed)
{
ErrorFunc(ErrorData);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to parse error response."));
}
}
}
);
}
template <typename ResponseStructType, typename ErrorResponseType>
static FOnResponseArrayReceived CreateArrayResponseDelegate(
const TFunction<void(const TArray<ResponseStructType>&, bool)>& SuccessFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc)
{
return FOnResponseArrayReceived::CreateLambda(
[SuccessFunc, ErrorFunc](const FHttpResponseData& HttpResponseData)
{
if (HttpResponseData.StatusCode >= 200 && HttpResponseData.StatusCode < 300)
{
TArray<ResponseStructType> ResponseData;
bool bSuccess = URoJson::JSONStringToUStructArray<ResponseStructType>(
HttpResponseData.Content, ResponseData);
UE_LOG(LogTemp, Warning, TEXT("响应 StatusCode: %d"), HttpResponseData.StatusCode);
UE_LOG(LogTemp, Warning, TEXT("响应 HttpResponseData.Content: %s"), *HttpResponseData.Content);
if (bSuccess)
{
SuccessFunc(ResponseData, bSuccess);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to parse success response."));
}
}
else
{
ErrorResponseType ErrorData;
bool bErrorParsed = URoJson::JSONStringToUStruct<ErrorResponseType>(
HttpResponseData.Content, ErrorData);
if (bErrorParsed)
{
ErrorFunc(ErrorData);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to parse error response."));
}
}
}
);
}
template <typename RequestStructType, typename ResponseStructType, typename ErrorResponseType>
static void Post(
const FString& Url,
const RequestStructType& RequestData,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
FString RequestBody;
URoJson::UStructToJSONString(RequestData, RequestBody);
// 更新 CreateResponseDelegate 调用,包含错误处理回调
auto ResponseDelegate = CreateResponseDelegate<ResponseStructType, ErrorResponseType>(ResponseFunc, ErrorFunc);
URoHttp::HttpRequest(Url, EHttpRequestMethod::POST, Headers, RequestBody, ResponseDelegate);
}
template <typename RequestStructType, typename ResponseStructType, typename ErrorResponseType>
static void PostArray(
const FString& Url,
const RequestStructType& RequestData,
const TFunction<void(const TArray<ResponseStructType>&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
FString RequestBody;
URoJson::UStructToJSONString(RequestData, RequestBody);
// 更新 CreateResponseDelegate 调用,包含错误处理回调
auto ResponseDelegate = CreateArrayResponseDelegate<ResponseStructType, ErrorResponseType>(
ResponseFunc, ErrorFunc);
URoHttp::HttpRequest(Url, EHttpRequestMethod::POST, Headers, RequestBody, ResponseDelegate);
}
template <typename ResponseStructType, typename ErrorResponseType>
static void Get(
const FString& Url,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
// 更新CreateResponseDelegate调用以包括错误处理回调
auto ResponseDelegate = CreateResponseDelegate<ResponseStructType, ErrorResponseType>(ResponseFunc, ErrorFunc);
// 假设GET请求不需要请求体
URoHttp::HttpRequest(Url, EHttpRequestMethod::GET, Headers, TEXT(""), ResponseDelegate);
}
template <typename ResponseStructType, typename ErrorResponseType>
static void GetArray(
const FString& Url,
const TFunction<void(const TArray<ResponseStructType>&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
// 更新CreateResponseDelegate调用以包括错误处理回调
auto ResponseDelegate = CreateArrayResponseDelegate<ResponseStructType, ErrorResponseType>(
ResponseFunc, ErrorFunc);
// 假设GET请求不需要请求体
URoHttp::HttpRequest(Url, EHttpRequestMethod::GET, Headers, TEXT(""), ResponseDelegate);
}
template <typename RequestStructType, typename ResponseStructType, typename ErrorResponseType>
static void Put(
const FString& Url,
const RequestStructType& RequestData,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
FString RequestBody;
URoJson::UStructToJSONString(RequestData, RequestBody);
auto ResponseDelegate = CreateResponseDelegate<ResponseStructType, ErrorResponseType>(ResponseFunc, ErrorFunc);
URoHttp::HttpRequest(Url, EHttpRequestMethod::PUT, Headers, RequestBody, ResponseDelegate);
}
template <typename ResponseStructType, typename ErrorResponseType>
static void Delete(
const FString& Url,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
auto ResponseDelegate = CreateResponseDelegate<ResponseStructType, ErrorResponseType>(ResponseFunc, ErrorFunc);
URoHttp::HttpRequest(Url, EHttpRequestMethod::DELETE, Headers, TEXT(""), ResponseDelegate);
}
template <typename RequestStructType, typename ResponseStructType, typename ErrorResponseType>
static void Patch(
const FString& Url,
const RequestStructType& RequestData,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const TFunction<void(const ErrorResponseType&)>& ErrorFunc,
FHttpHeaders Headers = FHttpHeaders()
)
{
URoHttpManager::ApplyGlobalHeaders(Headers);
FString RequestBody;
URoJson::UStructToJSONString(RequestData, RequestBody);
auto ResponseDelegate = CreateResponseDelegate<ResponseStructType, ErrorResponseType>(ResponseFunc, ErrorFunc);
URoHttp::HttpRequest(Url, EHttpRequestMethod::PATCH, Headers, RequestBody, ResponseDelegate);
}
};
Source/Ro2ea/Private/User/Http/RoHttpService.cpp
#include "User/Http/RoHttpService.h"
Source/Ro2ea/Public/User/Http/ServerExample.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "RoHttpManager.h"
#include "RoHttpService.h"
#include "ServerExample.generated.h"
//业务请求结构体
USTRUCT(BlueprintType)
struct FMyRequestStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Message;
};
//业务响应结构体
USTRUCT(BlueprintType)
struct FMyResponseStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString ResponseMessage;
};
// 自定义的错误响应
USTRUCT(BlueprintType)
struct FErrorResponseBody
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<FString> message;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString error;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 statusCode;
};
// 自定义结构体 用于转换为JSON字符串
USTRUCT(BlueprintType)
struct FPlayerData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
};
UCLASS()
class RO2EA_API UServerExample : public UObject
{
GENERATED_BODY()
public:
// 特定业务逻辑的封装方法
template <typename RequestStructType, typename ResponseStructType>
static void PostTestMessageService(
const RequestStructType& RequestData,
const TFunction<void(const ResponseStructType&, bool)>& ResponseFunc,
const FString& Url = TEXT("http://localhost:3000/users/test"), // 默认URL
FHttpHeaders Headers = FHttpHeaders() // 默认请求头
)
{
// 应用全局headers(比如Authentication token)
URoHttpManager::ApplyGlobalHeaders(Headers);
// 直接使用简化后的Post方法
URoHttpService::Post<RequestStructType, ResponseStructType>(
Url,
RequestData,
ResponseFunc,
Headers
);
}
// 业务逻辑服务: PostTestMessageService 的用例
// 使用方式 UServerExample::UsePostTestMessageService();
// 用例必须使用静态函数
// 实际项目使用模板,推荐
static void UsePostTestMessageService();
// URoHttpService::Post 工具函数用例 高级封装,支持结构体,更易用
static void UsePost();
// URoHttpStruct::HttpRequestWithStruct 工具函数用例 原始方法,增加了自定义结构体支持
static void UseHttpRequestWithStruct();
// URoHttp::HttpRequest 工具函数用例 原始方法
static void UseHttpRequest();
// URoHttpZ::HttpRequestPost 工具函数用例 原始方法
static void UseHttpRequestZPost();
// URoJson::UStructToJSONString URoJson::JSONStringToUStruct 自定义结构体与JSON字符串互转示例
static void UseRoJson();
};
Source/Ro2ea/Private/User/Http/ServerExample.cpp
#include "User/Http/ServerExample.h"
#include "User/Http/RoHttpStruct.h"
#include "User/Http/RoHttp.h"
#include "User/Http/RoHttpZ.h"
void UServerExample::UsePostTestMessageService()
{
FMyRequestStruct RequestData;
RequestData.Message = "UsePostTestMessageService!";
PostTestMessageService<FMyRequestStruct, FMyResponseStruct, FErrorResponseBody>(
RequestData,
[](const FMyResponseStruct& ResponseData, bool bWasSuccessful)
{
if (bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("Response Message: %s"), *ResponseData.ResponseMessage);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Request failed."));
}
},
[](const FErrorResponseBody& ErrorResponse)
{
UE_LOG(LogTemp, Error, TEXT("Error Message: %s"), *ErrorResponse.message[0]);
}
);
}
void UServerExample::UsePost()
{
FMyRequestStruct RequestData;
RequestData.Message = "URoHttpService::Post!";
URoHttpService::Post<FMyRequestStruct, FMyResponseStruct, FErrorResponseBody>(
TEXT("http://localhost:3000/users/test"),
RequestData,
[](const FMyResponseStruct& ResponseData, bool bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("Response Message: %s"), *ResponseData.ResponseMessage);
},
[](const FErrorResponseBody& ErrorResponse)
{
UE_LOG(LogTemp, Error, TEXT("Error Message: %s"), *ErrorResponse.message[0]);
}
);
}
void UServerExample::UseHttpRequestWithStruct()
{
//2 设置请求头和请求数据:
FHttpHeaders Headers;
Headers.SetHeader(TEXT("Content-Type"), TEXT("application/json"));
// 如果需要,设置其他头信息,比如Authorization
FMyRequestStruct RequestData;
RequestData.Message = TEXT("URoHttpStruct::HttpRequestWithStruct!");
//3 发送请求并处理响应:
URoHttpStruct::HttpRequestWithStruct<FMyRequestStruct, FMyResponseStruct>(
TEXT("http://localhost:3000/users/test"),
EHttpRequestMethod::POST,
Headers,
RequestData,
TDelegate<void(const FMyResponseStruct&, bool)>::CreateLambda(
[](const FMyResponseStruct& ResponseData, bool bWasSuccessful)
{
if (bWasSuccessful)
{
// 处理成功的响应
UE_LOG(LogTemp, Log, TEXT("Response Message: %s"), *ResponseData.ResponseMessage);
}
else
{
// 处理错误
UE_LOG(LogTemp, Error, TEXT("HTTP Request Failed"));
}
}));
}
void UServerExample::UseHttpRequest()
{
FHttpHeaders Headers;
Headers.SetHeader(TEXT("Content-Type"), TEXT("application/json"));
//Headers.Authorization = TEXT("Bearer your_token_here");
FString Body = TEXT("{\"key\":\"value - URoHttp::HttpRequest\"}");
FString URL = TEXT("http://localhost:3000/users/test");
FString UserToken = "some_dynamic_value";
URoHttp::HttpRequest(URL, EHttpRequestMethod::POST, Headers, Body, URoHttp::FOnResponseReceived::CreateLambda(
[](const FHttpResponseData& ResponseData)
{
if (ResponseData.StatusCode >= 200 && ResponseData.StatusCode <= 299)
{
// 处理成功的响应
UE_LOG(LogTemp, Log, TEXT("Response: %s"), *ResponseData.Content);
}
else
{
// 处理错误的响应
UE_LOG(LogTemp, Error, TEXT("HTTP Request Failed: %s"), *ResponseData.Content);
}
}));
}
void UServerExample::UseHttpRequestZPost()
{
FString Content2 = TEXT("{\"key2\":\"value2 - URoHttpZ::HttpRequestPost\"}");
URoHttpZ::HttpRequestPost(
TEXT("http://localhost:3000/users/test"), Content2, FOnHttpRequestCompleted::CreateLambda(
[](FHttpResponsePtr Response, bool bWasSuccessful)
{
if (bWasSuccessful && Response.IsValid())
{
// 处理响应内容
FString ResponseContent = Response->GetContentAsString();
UE_LOG(LogTemp, Log, TEXT("POST Response: %s"), *ResponseContent);
}
else
{
// 处理错误
UE_LOG(LogTemp, Error, TEXT("POST Request Failed"));
}
}));
}
void UServerExample::UseRoJson()
{
// 结构体转换为json字符串
FPlayerData PlayerData0;
PlayerData0.Name = TEXT("PlayerOne000");
FString JsonString0;
URoJson::UStructToJSONString(PlayerData0, JsonString0);
// json字符串转换为结构体
FPlayerData NewPlayerData0;
URoJson::JSONStringToUStruct(JsonString0, NewPlayerData0);
//
// 结构体转换为json字符串
FPlayerData PlayerData;
PlayerData.Name = FString("PlayerOne");
FString Content;
FJsonObjectConverter::UStructToJsonObjectString(FPlayerData::StaticStruct(), &PlayerData, Content, 0, 0);
UE_LOG(LogTemp, Warning, TEXT("结构体转换为json字符串: %s"), *Content);
// json字符串转换为结构体
FString JsonString = TEXT("{\"Name\":\"PlayerOne2222\"}");
FPlayerData PlayerData2;
if (FJsonObjectConverter::JsonObjectStringToUStruct<FPlayerData>(JsonString, &PlayerData2, 0, 0))
{
// 转换成功,PlayerData 现在被填充了 JSON 字符串中的数据
UE_LOG(LogTemp, Warning, TEXT("json字符串转换为结构体: %s"), *PlayerData2.Name);
}
else
{
// 处理转换失败的情况
UE_LOG(LogTemp, Warning, TEXT("json字符串转换为结构体失败"));
}
}
注意,仅作示例,BeginPlay() 可能会执行两次。
#include "User/Http/ServerExample.h"
void ARoCharacter::BeginPlay()
{
Super::BeginPlay();
//最终示例
//UServerExample ServerExample;
//ServerExample.UsePostTestMessageService();
UServerExample::UsePostTestMessageService();
UServerExample::UsePost();
UServerExample::UseHttpRequestWithStruct();
UServerExample::UseHttpRequest();
UServerExample::UseHttpRequestZPost();
UServerExample::UseRoJson();
}
虚幻引擎 插件 / Unreal Engine Plugins