【UE4 C++】HTTP 非同步請求 json 資料和下載檔案
阿新 • • 發佈:2021-11-02
- 前言
- 一般做個數據請求、或者下載檔案可以用到。當然也可以使用webSocket,或第三方庫,都可以,開心就好 _
- 本文只是用了 UBlueprintAsyncActionBase,也可以用多執行緒
- 本文沒有實現上傳檔案、且省略了post請求的使用
- 算是稍微重新整理吧
- 引擎版本:4.26.2
準備工作
-
.Build.cs 新增
HTTP
、Json
模組PrivateDependencyModuleNames.AddRange(new string[] { "HTTP", "Json" });
-
建立繼承 UBlueprintAsyncActionBase 的類
-
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" }, ... }
-
主要程式碼
-
標頭檔案
#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
#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(); }
-
-
藍圖部分和效果#
非同步下載檔案
-
主要程式碼 (本文地址)
-
標頭檔案
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
// 非同步下載 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); } }
-
-
藍圖及效果