- 前言
- 一般做個數據請求、或者下載文件可以用到。當然也可以使用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); } }
-
-
藍圖及效果