Best way to perform a http request?

I’ve been reading the docs and header files in Rocket for anything net-related, but most of it seems to be made for connections between Unreal servers and Unreal clients. I’m looking to perform a http request to a remote web server, receive whatever data, then process that for display. What would be the best way to go about doing this? Any help would be great - networking isn’t my strong point as a programmer!

Check out William Gaul’s Sagittarius project!

He has generously offered his entire source code for download where he shows ppl how to connect to their google app engine via http requests

http://forums.epicgames.com/threads/975387-Sagittarius-Online-Game-Service-in-UE4

in his source code be sure to specifically check out SagittariusLinkClient.h and .cpp

I have implemented his system in my game with complete success as you can read in the thread

Meaning, I have fully working http requests sending and receiving of data to remote server in my game thanks to William Gaul

:slight_smile:

Rama

PS: here is the entire source code from SagittariusLinkClient.h and .cpp, authored by William Gaul, edited by me to suit my game’s needs

.h

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "Sagittarius.h"
#include "Http.h"
#include "SagittariusLinkClient.generated.h"

//Sagittarius Request
	//changed to struct by Rama
USTRUCT()
struct FSagRequest
{
	GENERATED_USTRUCT_BODY()

	//Vars	
	UPROPERTY()
	FString TheDest;		
	
	UPROPERTY()
	FString TheData;		
	
	UPROPERTY()
	FString mID;
	
	UPROPERTY()
	FString qID;
	
	UPROPERTY()
	FString delim;
	
 	void AddURLPair(FString param, FString value)
	{
		TheData += (delim + param + "=" + value);
		delim = "&";
	}
	
	void SetDestination(FString& newDest)
	{
		TheDest = newDest;
	}

	//pass by ref its faster
	void SetModuleInfo(FString& newMID, FString& newQID)
	{
		mID = newMID;
		qID = newQID;
	}
	
	FSagRequest()
	{
		delim = ""; TheDest = ""; TheData = ""; mID = ""; qID = "";
	}
};

/**
 * Handles interfacing with the HTTP module to talk to our GAE app.
 *
 * @author: William Gaul
 */
UCLASS()
class USagittariusLinkClient : public UObject
{
	GENERATED_UCLASS_BODY()

	ASagittarius* Parent;
	FHttpModule* Http;
	FString TargetHost;
	bool bIsBusy;

	//Using Struct instead
	TArray RequestQueue;
	FSagRequest CurrentRequest;

public:
	void Initialize(ASagittarius* NewParent, FString THost);

	//pass struct by reference, safer than pointers
	void TransmitRequest(FSagRequest& request);
	void StartTransmission();

	void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
	void Closed(FString Message);
};

.cpp
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#include "VictoryGame.h"

#define VICTORY_SAG_MODULE_VIBE "VictoryGameSagittariusModule"

USagittariusLinkClient::USagittariusLinkClient(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	
}

void USagittariusLinkClient::Initialize(ASagittarius* NewParent, FString THost)
{
	// @TODO: If not available, then what?
	if (FHttpModule::IsAvailable())
	{
		Http = &FHttpModule::Get();
	}
	Parent = NewParent;
	TargetHost = FString::Printf(TEXT("http://%s.appspot.com"), *THost);
}

void USagittariusLinkClient::TransmitRequest(FSagRequest& request)
{	
	RequestQueue.Add(request); 		
										
	if (!bIsBusy)
	{
		StartTransmission();
	}
}

void USagittariusLinkClient::StartTransmission()
{
	//Always Check Your Pointers
	if (!Parent) return;
	//~~~~~~~~~~~~~
	
	if (RequestQueue.Num() <= 0)
	{
		return;
	}
	
	bIsBusy = true;
	CurrentRequest = RequestQueue[0];
	
	RequestQueue.RemoveAt(0);
	
	if (!Http) return;
	if(!Http->IsHttpEnabled()) return;
	//~~~~~~~~~~~~~~~~~~~~~~
	
	TSharedRef < IHttpRequest > Request = Http->CreateRequest(); 
	
	/**
	 * Instantiates a new Http request for the current platform
	 *
	 * @return new Http request instance
	 */
	//virtual TSharedRef CreateRequest();
	//~~~~~~~~~~~~~~~
	
	Request->SetVerb("POST");
	Request->SetURL(TargetHost + CurrentRequest.TheDest);
	Request->SetContentAsString(CurrentRequest.TheData);
	Request->SetHeader("User-Agent", "SagittariusLinkClient/1.0");
	Request->SetHeader("Content-Type" ,"application/x-www-form-urlencoded");

	Request->OnProcessRequestComplete().BindUObject(this, &USagittariusLinkClient::OnResponseReceived);
	if (!Request->ProcessRequest())
	{
		ASagittarius::LogError("Unable to process HTTP Request!");
	}
}

void USagittariusLinkClient::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	FString MessageBody = "";
		
	// If HTTP fails client-side, this will still be called but with a NULL shared pointer!
	if (!Response.IsValid())
	{
		MessageBody = "{\"success\":\"Error: Unable to process HTTP Request!\"}";
	}
	else if (EHttpResponseCodes::IsOk(Response->GetResponseCode()))
	{
		MessageBody = Response->GetContentAsString();
	}
	else
	{
		MessageBody = FString::Printf(TEXT("{\"success\":\"HTTP Error: %d\"}"), Response->GetResponseCode());
	}
	Closed(MessageBody);
}

void USagittariusLinkClient::Closed(FString Message)
{
	USagResponse* resp = NewObject();
	
	//Always Check Your Pointers
	if (!resp) return;
	if (!Parent) return;
	//~~~~~~~~~~~~~~~~~~
	
	resp->Decode(Message, Parent);
	Parent->OnResponseReceived(CurrentRequest.mID, CurrentRequest.qID, resp);
	bIsBusy = false;

	// Retry transmission in case there are any queued messages (if not, nothing happens)
	StartTransmission();
}

Thanks a bunch, this will definitely help!

Let us know if Rama’s answer did not solve the issue for you and you require further assistance.

Cheers!

Rama’s answer worked - I stripped down Sagittarius to find what core functionality I needed, and now I’m communicating happily with the server in question. I’m only able to work on the code once a week, so I’ll post my (admittedly simple) solution when I get the chance, for others to reference.

Good use of EHttpResponseCodes::IsOk. Better than checking individual response codes