【虚幻引擎】UE4 Http之异步请求数据

8 篇文章 11 订阅

B站教学链接:https://space.bilibili.com/449549424?spm_id_from=333.1007.0.0


一、BlueprintAsyncActionBase

  UE提供了BlueprintAsyncActionBase类,实现异步加载的方式请求数据

虚幻的很多蓝图节点都采用了异步加载的方式

比如:延迟Delay,PlayMontage都是采用异步加载的方式进行实现

接下我们就用异步加载的方式实现HTTP请求下载

二、HTTP请求

新建一个C++项目,然后build.cs加入模块

		PrivateDependencyModuleNames.AddRange(new string[] { "HTTP", "Json" });

 创建继承自BlueprintAsyncActionBase的C++类

请求的Json格式的数据为

 代理声明:代理参数跟我们后面函数的输出参数有关,要想输出函数参数,需要在代理的位置声明返回参数

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FRequestCompleteDelegate, const TArray<FNewsItem>&, Data,int32, ver);

 

 输出节点如OnSucceeded,OnFailed这些节点跟我们声明的代理有关,就是代理声明的对象

//输出节点
	UPROPERTY(BlueprintAssignable)
		FRequestCompleteDelegate OnSucceeded;

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FRequestCompleteDelegate OnFailed;

 

 主要代码如下MyBlueprintAsyncActionBase.h文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Interfaces/IHttpRequest.h"
#include "MyBlueprintAsyncActionBase.generated.h"


USTRUCT(BlueprintType)
struct FNewsItem {
	GENERATED_USTRUCT_BODY()

		FNewsItem() {}
	FNewsItem(FString _Path, FString _Url)
		: Path(_Path), Url(_Url) {}
	UPROPERTY(BlueprintReadOnly)
		FString Path;
	UPROPERTY(BlueprintReadOnly)
		FString Url;
};

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FRequestCompleteDelegate, const TArray<FNewsItem>&, Data,int32, ver);


/**
 * 
 */
UCLASS()
class TEST111_API UMyBlueprintAsyncActionBase : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()
	
	UMyBlueprintAsyncActionBase();

	//json
public:

	// 自定义的异步蓝图节点
	UFUNCTION(BlueprintCallable, Category = "AsyncHttp", meta = (BlueprintInternalUseOnly = "true"))
		static UMyBlueprintAsyncActionBase* AsyncHttpURLRequest(const FString& url);

	void HttpRequestStar(const FString& url);
	void HttpRequest_RecHandle(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful);

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FRequestCompleteDelegate OnSucceeded;

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FRequestCompleteDelegate OnFailed;


	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Version")
		int32 version;

};

MyBlueprintAsyncActionBase.cpp文件

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyBlueprintAsyncActionBase.h"
#include "HttpModule.h"
#include "Interfaces/IHttpResponse.h"

UMyBlueprintAsyncActionBase::UMyBlueprintAsyncActionBase()
{
	if (HasAnyFlags(RF_ClassDefaultObject) == false)
	{
		AddToRoot(); //防止自动GC
	}
}

UMyBlueprintAsyncActionBase* UMyBlueprintAsyncActionBase::AsyncHttpURLRequest(const FString& url) {
	UMyBlueprintAsyncActionBase* AsyncHttpObject = NewObject<UMyBlueprintAsyncActionBase>();
	AsyncHttpObject->HttpRequestStar(url);
	return AsyncHttpObject;
}

//开始请求
void UMyBlueprintAsyncActionBase::HttpRequestStar(const FString& url)
{
	TSharedRef<IHttpRequest, ESPMode::ThreadSafe> request = FHttpModule::Get().CreateRequest();
	request->SetVerb("GET");
	request->SetURL(url);
	//request->SetHeader(TEXT("Content-Type"), TEXT("application/json;charset=utf-8"));
	//request->SetTimeout(200);
	//request->SetContentAsString(requestJsonStr); POST时候用
	//request->OnRequestProgress().BindUObject() 绑定进度
	request->OnProcessRequestComplete().BindUObject(this, &UMyBlueprintAsyncActionBase::HttpRequest_RecHandle); //请求回调
	request->ProcessRequest();
}
//请求回调
void UMyBlueprintAsyncActionBase::HttpRequest_RecHandle(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful) {


	if (bWasSuccessful && response.IsValid() && EHttpResponseCodes::IsOk(response->GetResponseCode())) {
		TSharedPtr<FJsonObject> jsonObj;
		TSharedRef<TJsonReader<>> JsonReader = TJsonReaderFactory<>::Create(response->GetContentAsString());

		if (FJsonSerializer::Deserialize(JsonReader, jsonObj)) {
			version = jsonObj->GetIntegerField("versionId");
			UE_LOG(LogTemp, Warning, TEXT("version is %d"), version);
			const TArray< TSharedPtr<FJsonValue> >* dataList;
			if (jsonObj->TryGetArrayField(TEXT("DataList"), dataList)) // 获取数组
			{
				TArray<FNewsItem> newsList;
				for (TSharedPtr<FJsonValue> item : *dataList)
				{
					TSharedPtr<FJsonObject>itemObjet = item->AsObject();

					newsList.Add(FNewsItem(
						itemObjet->GetStringField(TEXT("Path")),
						itemObjet->GetStringField(TEXT("Url"))
					));
				}
				OnSucceeded.Broadcast(newsList, version); // 成功的执行
				RemoveFromRoot();
				return;
			}
		}
	}
	OnFailed.Broadcast({},0); // 失败的执行
	RemoveFromRoot();
}

打开关卡蓝图:

 三、HTTP下载

这里我重新建了一个继承自BlueprintAsyncActionBase的类

TestBlueprintAsyncActionBase.h文件

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "Interfaces/IHttpRequest.h"
#include "TestBlueprintAsyncActionBase.generated.h"


/**
 * 
 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDownloadProgressDelegate1,
const int32&, ReceivedDataInBytes,
const int32&, TotalDataInBytes,
const TArray<uint8>&, BinaryData
);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDownloadDelegate1);

UCLASS()
class TEST111_API UTestBlueprintAsyncActionBase : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()

	UTestBlueprintAsyncActionBase();
public:
	//load data

	UFUNCTION(BlueprintCallable, Category = "MyAsyncHttp", meta = (BlueprintInternalUseOnly = "true"))
		static UTestBlueprintAsyncActionBase* AsyncHttpDownload(const FString& url);

	void DownloadRequestStart(const FString& url);
	void DownloadRequestHandle(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful);
	void DownloadProgress(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived);

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FDownloadProgressDelegate1 OnProgressUpdate; //最好把有参数的放在前面,不然参数在蓝图节点有时候被吃掉了

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FDownloadDelegate1 Load_Ok;

	//输出节点
	UPROPERTY(BlueprintAssignable)
		FDownloadDelegate1 Load_Fail;
};

TestBlueprintAsyncActionBase.cpp文件 

// Fill out your copyright notice in the Description page of Project Settings.


#include "TestBlueprintAsyncActionBase.h"
#include "HttpModule.h"
#include "Interfaces/IHttpResponse.h"

UTestBlueprintAsyncActionBase::UTestBlueprintAsyncActionBase()
{
	if (HasAnyFlags(RF_ClassDefaultObject) == false)
	{
		AddToRoot(); //防止自动GC
	}
}

UTestBlueprintAsyncActionBase* UTestBlueprintAsyncActionBase::AsyncHttpDownload(const FString& url)
{
	UTestBlueprintAsyncActionBase* AsyncHttpObject = NewObject<UTestBlueprintAsyncActionBase>();
	AsyncHttpObject->DownloadRequestStart(url);
	return AsyncHttpObject;
}

void UTestBlueprintAsyncActionBase::DownloadRequestStart(const FString& url)
{
	TSharedRef<IHttpRequest, ESPMode::ThreadSafe> request = FHttpModule::Get().CreateRequest();
	request->SetVerb("GET");
	request->SetURL(url);
	request->OnProcessRequestComplete().BindUObject(this, &UTestBlueprintAsyncActionBase::DownloadRequestHandle); //请求回调
	request->OnRequestProgress().BindUObject(this, &UTestBlueprintAsyncActionBase::DownloadProgress);// 下载进度
	request->ProcessRequest();

	RemoveFromRoot(); // 手动GC
}

void UTestBlueprintAsyncActionBase::DownloadRequestHandle(FHttpRequestPtr request, FHttpResponsePtr response, bool bWasSuccessful)
{
	RemoveFromRoot();


	if (bWasSuccessful && response.IsValid() && EHttpResponseCodes::IsOk(response->GetResponseCode()))
	{
		if (response->GetContentLength() > 0) {
			TArray<uint8> EmptyData;
			OnProgressUpdate.Broadcast(response->GetContentLength(), response->GetContentLength(), EmptyData);
		}

		FString FileSavePath = FPaths::ProjectDir() + "/download/gameplay.png";
		FString Path, Filename, Extension;
		FPaths::Split(FileSavePath, Path, Filename, Extension);
		IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();

		if (!PlatformFile.DirectoryExists(*Path))
		{
			if (!PlatformFile.CreateDirectoryTree(*Path))
			{
				UE_LOG(LogTemp, Error, TEXT("Create Directory Failed!"));
				Load_Fail.Broadcast();
				return;
			}
		}

		IFileHandle* FileHandle = PlatformFile.OpenWrite(*FileSavePath);
		if (FileHandle)
		{
			FileHandle->Write(response->GetContent().GetData(), response->GetContentLength());
			delete FileHandle;
			Load_Ok.Broadcast();
			return;
		}
		else {
			UE_LOG(LogTemp, Error, TEXT("Save File Failed!"));
			Load_Fail.Broadcast();
			return;
		}

	}
	UE_LOG(LogTemp, Error, TEXT("download File Failed!"));
	Load_Fail.Broadcast();
	return;
}

void UTestBlueprintAsyncActionBase::DownloadProgress(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived)
{
	if (request->GetResponse()->GetContentLength() > 0)
	{
		TArray<uint8> EmptyData;
		OnProgressUpdate.Broadcast(bytesReceived, request->GetResponse()->GetContentLength(), EmptyData);
	}
}


打开关卡蓝图设置:

 注意这里图片下载的位置在项目工程里新建了一个download的文件夹里面

FString FileSavePath = FPaths::ProjectDir() + "/download/gameplay.png";

 

 

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞起的猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值