【UE4 C++】HTTP 异步请求 json 数据和下载文件
- 前言
- 一般做个数据请求、或者下载文件可以用到。当然也可以使用webSocket,或第三方库,都可以,开心就好 _
- 本文只是用了 UBlueprintAsyncActionBase,也可以用多线程
- 本文没有实现上传文件、且省略了post请求的使用
- 算是稍微重新整理吧
- 引擎版本:4.26.2
- 原文地址
准备工作
-
.Build.cs 添加
HTTP
、Json
模块PrivateDependencyModuleNames.AddRange(new string[] { "HTTP", "Json" });
-
创建继承 UBlueprintAsyncActionBase 的类
-
Json 解析,参考 【UE4 C++】 解析与构建 Json 数据
-
异步蓝图节点,参考 【UE4 C++】异步蓝图节点
请求 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); } }
-
-
蓝图及效果
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!