SoFunction
Updated on 2025-03-07

C# implements the reverse proxy tool instance that can cache web pages to local

This article describes the C# implementation of a reverse proxy tool that can cache web pages to the local area. Share it for your reference. The specific implementation method is as follows:

Main file:

<%@ WebHandler Language="C#" Class="proxy" %>
using System;
using ;
using ;
using ;
using ;
using ;
using ;
/// <summary>
///Storing the contents of http headers and http responses in /proxy/header/ and /proxy/body/ respectively/// Create a directory in hierarchy/// </summary>
public class proxy : IHttpHandler
{
 HttpResponse Response;
 HttpRequest Request;
 HttpApplicationState Application;
 HttpServerUtility Server;
 static string proxyCacheFolder = ["proxyCacheFolder"];
 static string proxyDomain = ["proxyDomain"];
 static string proxyReferer = ["proxyReferer"];
 bool proxyCacheDirectAccess = ["proxyCacheDirectAccess"] == "true";
 int proxyCacheSeconds = (["proxyCacheSeconds"]);
 public void ProcessRequest(HttpContext context)
 {
  Response = ;
  Request = ;
  Application = ;
  Server = ;
  string path = ;
  bool delCache = ("?del") > 0;
  if (delCache)
  {
   path = ("?del", );
   DeleteCacheFile(path);
   return;
  }
  bool allowCache = ["cache"] == "true";
  string seconds = ["seconds"] ?? ;
  if (!(seconds, out proxyCacheSeconds))
  {
   proxyCacheSeconds = 3600;
  }
  if (allowCache)
  {
   EchoData(path);
  }
  else
  {
   WebClient wc = new WebClient();
   ("Referer", proxyReferer);
   byte[] buffer = (proxyDomain + path);
    = ["Content-Type"];
   foreach (string key in )
   {
    (key, [key]);
   }
   ();
   (buffer, 0, );
  }
 }
 /// <summary>
 /// Clean up invalid cache /// </summary>
 /// <param name="d"></param>
 void ClearTimeoutCache(DirectoryInfo d)
 {
  if ()
  {
   FileInfo[] files = ();
   foreach (FileInfo file in files)
   {
    TimeSpan timeSpan =  - ;
    if ( > proxyCacheSeconds)
    {
     ();
    }
   }
  }
 }
 string GetCacheFolderPath(string hash)
 {
  string s = ;
  for (int i = 0; i <= 2; i++)
  {
   s += hash[i] + "/";
  }
  return s;
 }
 /// <summary>
 /// Read the cached header and output it /// </summary>
 /// <param name="cacheHeaderPath"></param>
 void EchoCacheHeader(string cacheHeaderPath)
 {
  string[] headers = (cacheHeaderPath);
  for (int i = 0; i < ; i++)
  {
   string[] headerKeyValue = headers[i].Split(':');
   if ( == 2)
   {
    if (headerKeyValue[0] == "Content-Type")
    {
      = headerKeyValue[1];
    }
    (headerKeyValue[0], headerKeyValue[1]);
   }
  }
 }
 void DeleteCacheFile(string path)
 {
  string absFolder = (proxyCacheFolder);
  string hash = GetHashString(path);
  string folder = GetCacheFolderPath(hash);
  string cacheBodyPath = absFolder + "/body/" + folder + hash;
  string cacheHeaderPath = absFolder + "/header/" + folder + hash;
  FileInfo cacheBody = new FileInfo(cacheBodyPath);
  FileInfo cacheHeader = new FileInfo(cacheHeaderPath);
  if ()
  {
   ();
  }
  if ()
  {
   ();
  }
  ("delete cache file Success!\r\n" + path);
 }
 /// <summary>
 /// Output cache /// </summary>
 /// <param name="cacheHeaderPath">File path to cache header</param> /// <param name="cacheBodyPath">File path to cache body</param> /// <param name="ifTimeout">Whether to determine the file expired</param> /// <returns> Is the output successful?</returns> bool EchoCacheFile(string cacheHeaderPath, string cacheBodyPath, bool ifTimeout)
 {
  FileInfo cacheBody = new FileInfo(cacheBodyPath);
  FileInfo cacheHeader = new FileInfo(cacheHeaderPath);
  ClearTimeoutCache();
  ClearTimeoutCache();
  if ( &amp;&amp; )
  {
   if (ifTimeout)
   {
    TimeSpan timeSpan =  - ;
    if ( &lt; proxyCacheSeconds)
    {
     EchoCacheHeader(cacheHeaderPath);
     (cacheBodyPath);
     return true;
    }
   }
   else
   {
    EchoCacheHeader(cacheHeaderPath);
    (cacheBodyPath);
    return true;
   }
  }
  return false;
 }
 void EchoData(string path)
 {
  string absFolder = (proxyCacheFolder);
  string hash = GetHashString(path);
  string folder = GetCacheFolderPath(hash);
  string cacheBodyPath = absFolder + "/body/" + folder + hash;
  string cacheHeaderPath = absFolder + "/header/" + folder + hash;
  bool success;
  if (proxyCacheDirectAccess)
  {
   success = EchoCacheFile(cacheHeaderPath, cacheBodyPath, false);
   if (!success)
   {
    ("Failed to read directly from cache!");
   }
   return;
  }
  success = EchoCacheFile(cacheHeaderPath, cacheBodyPath, true);
  if (success)
  {
   return;
  }
  //Update Cache File  string ApplicationKey = "CacheList";
  List&lt;string&gt; List = null;
  if (Application[ApplicationKey] == null)
  {   
   ();
   Application[ApplicationKey] = List = new List&lt;string&gt;(1000);
   ();
  }
  else
  {
   List = (List&lt;string&gt;)Application[ApplicationKey];
  }
  //Judge whether another process is updating the Cache File  if ((hash))
  {
   success = EchoCacheFile(cacheHeaderPath, cacheBodyPath, false);
   if (success)
   {
    return;
   }
   else
   {
    WebClient wc = new WebClient();
    ("Referer", proxyReferer);
    // Subject content    byte[] data = (proxyDomain + path);
    //Processing header     = ["Content-Type"];
    foreach (string key in )
    {
     (key, [key]);
    }
    ();
    (data);
   }
  }
  else
  {
   WebClient wc = new WebClient();
   ("Referer", proxyReferer);
   StringBuilder headersb = new StringBuilder();
   (hash);
   // Subject content   byte[] data = (proxyDomain + path);
   //Processing header    = ["Content-Type"];
   foreach (string key in )
   {
    (key);
    (":");
    ([key]);
    ("\r\n");
    (key, [key]);
   }
   ();
   string headers = ().Trim();
   if (!(absFolder + "/header/" + folder))
   {
    (absFolder + "/header/" + folder);
   }
   StreamWriter sw = (absFolder + "/header/" + folder + hash);
   (headers);
   ();
   ();
   //Processing cached content   if (!(absFolder + "/body/" + folder))
   {
    (absFolder + "/body/" + folder);
   }
   FileStream fs = (absFolder + "/body/" + folder + hash);
   (data, 0, );
   ();
   ();
   (hash);
   (data);
  }
 }
 string GetHashString(string path)
 {
  string md5 = GetMd5Str(path);
  return md5;
 }
 static string GetMd5Str(string ConvertString)
 {
  .MD5CryptoServiceProvider md5 = new .MD5CryptoServiceProvider();
  string t2 = (((ConvertString)), 4, 8);
  t2 = ("-", "");
  return t2;
 }
 public bool IsReusable
 {
  get
  {
   return false;
  }
 }
}

The file is as follows:

&lt;?xml version="1.0"?&gt;
&lt;configuration&gt;
 &lt;configSections&gt;
 &lt;section name="RewriterConfig" type=", URLRewriter"/&gt; 
 &lt;/configSections&gt;
 &lt;RewriterConfig&gt;
 &lt;Rules&gt;
  &lt;RewriterRule&gt;
  &lt;LookFor&gt;~/.*$&lt;/LookFor&gt;
  &lt;SendTo&gt;
  &lt;!--cache=true Set this path for cache--&gt;
   &lt;![CDATA[~/?cache=true&amp;seconds=30]]&gt;
  &lt;/SendTo&gt;
  &lt;/RewriterRule&gt;
  &lt;RewriterRule&gt;
  &lt;LookFor&gt;~/ajax/.*$&lt;/LookFor&gt;
  &lt;SendTo&gt;
  &lt;!--cache=false Setting this path does not allow cache--&gt;
   &lt;![CDATA[~/?cache=false]]&gt;
  &lt;/SendTo&gt;
  &lt;/RewriterRule&gt;
 &lt;/Rules&gt;
 &lt;/RewriterConfig&gt;
 &lt;appSettings&gt;
 &lt;!--#Reverse proxy settings start--> &lt;!--Set up a site--&gt;
 &lt;add key="proxyDomain" value="http://127.0.0.1:12123/"/&gt;
 &lt;!--Cache folder--&gt;
 &lt;add key="proxyCacheFolder" value="/proxyCache/"/&gt;
 &lt;!--Cache duration--&gt;
 &lt;add key="proxyCacheSeconds" value="3600"/&gt;
 &lt;!--Setting no longer determines whether the cached file is timed out,Read directly from the cache--&gt;
 &lt;add key="proxyCacheDirectAccess" value="false"/&gt;
 &lt;!--Set up a reverse proxyReferer--&gt;
 &lt;add key="proxyReferer" value="/"/&gt;
 &lt;!--#Reverse proxy settings end--> &lt;/appSettings&gt;
 &lt;&gt;
 &lt;modules runAllManagedModulesForAllRequests="true"&gt;
  &lt;add type=", URLRewriter" name="ModuleRewriter"/&gt;
 &lt;/modules&gt;
 &lt;/&gt;
 &lt;&gt;
 &lt;compilation debug="true"/&gt;
 &lt;/&gt;
&lt;/configuration&gt;

I hope this article will be helpful to everyone's C# programming.