C# - Purge Cached Files In Cloudflare Using the API
I, like many others use Cloudflare for my website.cEssentially all web requests to https://andyp.dev are proxied via Cloudflare's servers.
This comes with some benefits, one of the main one's being that static resources such as Javascript and CSS files can be cached and served from Cloudflare's servers instead of mine. This reduces the load on my server and the amout of consumed bandwidth. While at the same time (hopefully) improving the page load times for users like you.
Why Purge The Cache
You can configure the amount of time that Cloudflare instructs a visitors browser to cache files from the web portal. The browser should then cache the served static resources from your site offline, for the specified amount of time. So if your Cache TTl is set to 1 hour and a user re-visits a page within the hour, the browser won't need to contact Cloudflare or your server to download the static Javascript, CSS and images.
I recently worked on a project that required a bunch .jpg files to be cleared from the cache every time they were updated from a CMS. You can clear files from the cache via the Cloudflare web portal, however this is time consuming and the people uploading the file's won't neseserily have access to the portal.
Purging The Cache
I decided to code a method that would clear the file from the cache when it is updated.
Prerequsits
- You need to get an API get from Cloudflare before this will work.
- I'm using Newtonsoft.Json to handle the JSON request/response. You will need to add the Newtonsoft.Json Nuget package to your project.
- My example was written in C# using .NET Core 3.1.
The Code
You'll find the code I used below.
/// <summary>
/// Forward request to cloudflare
/// </summary>
/// <param name="url"></param>
private static bool SendPurgeRequest(List<string> urls)
{
// Initializations
var key = "Enter Your Key Here";
var zoneId = "Enter Your Zone Id Here";
var baseUrl = "https://api.cloudflare.com/client/v4/zones/";
CloudflarePurgeResponse purgeResponse = null;
// Create HttpWebRequest
HttpWebRequest purgeRequest = WebRequest.CreateHttp($"{baseUrl}{zoneId}/purge_cache");
purgeRequest.Method = "POST";
purgeRequest.ContentType = "application/json";
purgeRequest.Headers.Add("Authorization", "Bearer " + key);
#region Create list of Files for Submission In The Structure The Response Requires
CloudflareFileInfo fileInfo = new CloudflareFileInfo
{
Files = urls
};
byte[] data = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(fileInfo));
purgeRequest.ContentLength = data.Length;
using (Stream fileStream = purgeRequest.GetRequestStream())
{
fileStream.Write(data, 0, data.Length);
fileStream.Flush();
}
#endregion
using (WebResponse response = purgeRequest.GetResponse())
{
using (StreamReader purgeStream = new StreamReader(response.GetResponseStream()))
{
string responseJson = purgeStream.ReadToEnd();
if (!string.IsNullOrEmpty(responseJson))
purgeResponse = JsonConvert.DeserializeObject<CloudflarePurgeResponse>(responseJson);
}
}
if (purgeResponse.Success)
return true;
return false;
}
And these are the Models that i've placed in a separate file.
public class CloudflareFileInfo
{
[JsonProperty("files")]
public List<string> Files { get; set; }
}
public class CloudflareZone
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
[JsonProperty("proxiable")]
public bool Proxiable { get; set; }
[JsonProperty("proxied")]
public bool Proxied { get; set; }
[JsonProperty("ttl")]
public int Ttl { get; set; }
[JsonProperty("priority")]
public int Priority { get; set; }
[JsonProperty("locked")]
public bool Locked { get; set; }
[JsonProperty("zone_id")]
public string ZoneId { get; set; }
[JsonProperty("zone_name")]
public string ZoneName { get; set; }
[JsonProperty("modified_on")]
public DateTime ModifiedOn { get; set; }
[JsonProperty("created_on")]
public DateTime CreatedOn { get; set; }
}
public class CloudflarePurgeResultInfo
{
[JsonProperty("page")]
public int Page { get; set; }
[JsonProperty("per_page")]
public int PerPage { get; set; }
[JsonProperty("count")]
public int Count { get; set; }
[JsonProperty("total_count")]
public int TotalCount { get; set; }
}
public class CloudflarePurgeResponse
{
[JsonProperty("result")]
public CloudflareZone Result { get; set; }
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("errors")]
public IList<object> Errors { get; set; }
[JsonProperty("messages")]
public IList<object> Messages { get; set; }
[JsonProperty("result_info")]
public CloudflarePurgeResultInfo ResultInfo { get; set; }
}
The Explanation
The method requires you to pass in a list of strings. You will also need to enter your API key and Cloudflare Zone Id here.
var key = "Enter Your Key Here";
var zoneId = "Enter Your Zone Id Here";
You'll notice that the method then creates a HttpWebRequest and serializes the list of URL's into JSON.
After forwarding the request to the Cloudflare API, the method then deserializes the result before returning either a true or false result based on the response from the API.