【UE4 C++】HTTP 异步请求 json 数据和下载文件

  • 前言
    • 一般做个数据请求、或者下载文件可以用到。当然也可以使用webSocket,或第三方库,都可以,开心就好 _
    • 本文只是用了 UBlueprintAsyncActionBase,也可以用多线程
    • 本文没有实现上传文件、且省略了post请求的使用
    • 算是稍微重新整理吧
  • 引擎版本:4.26.2
  • 原文地址

准备工作

请求 json 数据

  • 请求的 json 格式,url 为 https://docs.tenapi.cn/zhihuresou.html#请求示例

    {
      "data": 200,
      "list": [
        {
          "name": "notability",
          "query": "Notability 年费订阅制",
          "url": "https://www.zhihu.com/search?q=notability&utm_content=search_hot&type=content"
        },
        {
          "name": "马斯克",
          "query": "马斯克中文发《七步诗》",
          "url": "https://www.zhihu.com/search?q=%E9%A9%AC%E6%96%AF%E5%85%8B&utm_content=search_hot&type=content"
        },
        ...
    }
    
  • 主要代码

    • 头文件

      //@ https://www.cnblogs.com/shiroe/p/15500780.html
      #pragma once
      #include "CoreMinimal.h"
      #include "Kismet/BlueprintAsyncActionBase.h"
      #include "Interfaces/IHttpRequest.h"
      #include "AsyncHttpObject.generated.h"
      
      USTRUCT(BlueprintType)
      struct FNewsItem {
      	 GENERATED_USTRUCT_BODY()
      
      	FNewsItem() {}
      	FNewsItem(FString _key, FString _title, FString _url)
      		: key(_key), title(_title), url(_url) {}
      	UPROPERTY(BlueprintReadOnly)
      		FString key;
      	UPROPERTY(BlueprintReadOnly)
      		FString title;
      	UPROPERTY(BlueprintReadOnly)
      		FString url;
      };
      
      // 定义委托,作为返回
      DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FRequestCompleteDelegate, const TArray<FNewsItem>&, Data); //注意此处的参数类型
      
      UCLASS()
      class RUBIKSCUBE_API UAsyncHttpObject : public UBlueprintAsyncActionBase
      {
      	GENERATED_BODY()
      		
      public:
      	UAsyncHttpObject();
      	// 自定义的异步蓝图节点
      	UFUNCTION(BlueprintCallable, Category = "AsyncHttp", meta=( BlueprintInternalUseOnly="true" ))
      		static UAsyncHttpObject* 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;
      
      };
      
    • cpp

      //@ https://www.cnblogs.com/shiroe/p/15500780.html
      #include "AsyncHttpObject.h"
      #include "HttpModule.h"
      #include "Interfaces/IHttpResponse.h"
      
      UAsyncHttpObject::UAsyncHttpObject()
      {
      	if (HasAnyFlags(RF_ClassDefaultObject) == false)
      	{
      		AddToRoot(); //防止自动GC
      	}
      }
      
      UAsyncHttpObject* UAsyncHttpObject::AsyncHttpURLRequest( const FString& url) {
      	UAsyncHttpObject* AsyncHttpObject = NewObject<UAsyncHttpObject>();
      	AsyncHttpObject->HttpRequestStar(url);	
      	return AsyncHttpObject;
      }
      
      //开始请求
      void UAsyncHttpObject::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, &UAsyncHttpObject::HttpRequest_RecHandle); //请求回调
      	request->ProcessRequest();
      }
      //请求回调
      void UAsyncHttpObject::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)) {
      			const TArray< TSharedPtr<FJsonValue> >* dataList;
      			if (jsonObj->TryGetArrayField(TEXT("list"), dataList)) // 获取数组
      			{
      				TArray<FNewsItem> newsList;
      				for (TSharedPtr<FJsonValue> item : *dataList)
      				{
      					TSharedPtr<FJsonObject>itemObjet = item->AsObject();
      
      					newsList.Add(FNewsItem(
      						itemObjet->GetStringField(TEXT("name")),
      						itemObjet->GetStringField(TEXT("query")),
      						itemObjet->GetStringField(TEXT("url"))
      						));
      				}
      				OnSucceeded.Broadcast(newsList); // 成功的执行
      				RemoveFromRoot();
      				return;
      			}
      		}
      	}
      	OnFailed.Broadcast({}); // 失败的执行
      	RemoveFromRoot();
      }
      
  • 蓝图部分和效果#

异步下载文件

  • 主要代码 (本文地址)

    • 头文件

      //@ https://www.cnblogs.com/shiroe/p/15500780.html
      DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FDownloadProgressDelegate,
      const int32&, ReceivedDataInBytes,
      const int32&, TotalDataInBytes,
      const TArray<uint8>&, BinaryData
      );
      DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDownloadDelegate);
      
      // 异步下载文件
      	UFUNCTION(BlueprintCallable, Category = "AsyncHttp", meta = (BlueprintInternalUseOnly = "true"))
      		static UAsyncHttpObject* 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)
      		FDownloadProgressDelegate OnProgressUpdate; //最好把有参数的放在前面,不然参数在蓝图节点有时候被吃掉了
      
      	//输出节点
      	UPROPERTY(BlueprintAssignable)
      		FDownloadDelegate OnSucc;
      
      	//输出节点
      	UPROPERTY(BlueprintAssignable)
      		FDownloadDelegate OnFailed;
      
    • cpp

      //@ https://www.cnblogs.com/shiroe/p/15500780.html
      // 异步下载
      UAsyncHttpObject* UAsyncHttpObject::AsyncHttpDownload(const FString& url)
      {
      	UAsyncHttpObject* AsyncHttpObject = NewObject<UAsyncHttpObject>();
      	AsyncHttpObject->DownloadRequestStart(url);
      	return AsyncHttpObject;
      }
      
      //开始请求下载
      void UAsyncHttpObject::DownloadRequestStart(const FString& url)
      {
      	TSharedRef<IHttpRequest, ESPMode::ThreadSafe> request = FHttpModule::Get().CreateRequest();
      	request->SetVerb("GET");
      	request->SetURL(url);
      	request->OnProcessRequestComplete().BindUObject(this, &UAsyncHttpObject::DownloadRequestHandle); //请求回调
      	request->OnRequestProgress().BindUObject(this, &UAsyncHttpObject::DownloadProgress);// 下载进度
      	request->ProcessRequest();
      
      	RemoveFromRoot(); // 手动GC
      }
      
      ////请求回调
      void UAsyncHttpObject::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!"));
      				OnFailed.Broadcast();
      				return;
      			}
      		}
      
      		IFileHandle* FileHandle = PlatformFile.OpenWrite(*FileSavePath);
      		if (FileHandle)
      		{
      			FileHandle->Write(response->GetContent().GetData(), response->GetContentLength());
      			delete FileHandle;
      			OnSucc.Broadcast();
      			return;
      		}
      		else {
      			UE_LOG(LogTemp, Error, TEXT("Save File Failed!"));
      			OnFailed.Broadcast();
      			return;
      		}
      			
      	}		
      	UE_LOG(LogTemp, Error, TEXT("download File Failed!"));
      	OnFailed.Broadcast();
      	return;
      }
      
      // 下载进度
      void UAsyncHttpObject::DownloadProgress(FHttpRequestPtr request, int32 bytesSent, int32 bytesReceived)
      {
      	if (request->GetResponse()->GetContentLength() > 0)
      	{
      		TArray<uint8> EmptyData;
      		OnProgressUpdate.Broadcast(bytesReceived, request->GetResponse()->GetContentLength(),EmptyData);
      	}
      }
      
  • 蓝图及效果

posted @ 2021-11-02 20:01  砥才人  阅读(3547)  评论(0编辑  收藏  举报