本文實例講述了C#實現可緩存網頁到本地的反向代理工具。分享給大家供大家參考。具體實現方法如下:
proxy.ashx 主文件:
<%@ WebHandler Language="C#" Class="proxy" %>using System;using System.Web;using System.Net;using System.Text;using System.IO;using System.Collections.Generic;using System.Configuration;/// <summary>/// 把http headers 和 http 響應的內容 分別存儲在 /proxy/header/ 和 /proxy/body/ 中/// 分層次創建目錄/// </summary>public class proxy : IHttpHandler{ HttpResponse Response; HttpRequest Request; HttpApplicationState Application; HttpServerUtility Server; static string proxyCacheFolder = ConfigurationManager.AppSettings["proxyCacheFolder"]; static string proxyDomain = ConfigurationManager.AppSettings["proxyDomain"]; static string proxyReferer = ConfigurationManager.AppSettings["proxyReferer"]; bool proxyCacheDirectAccess = ConfigurationManager.AppSettings["proxyCacheDirectAccess"] == "true"; int proxyCacheSeconds = int.Parse(ConfigurationManager.AppSettings["proxyCacheSeconds"]); public void ProcessRequest(HttpContext context) {  Response = context.Response;  Request = context.Request;  Application = context.Application;  Server = context.Server;  string path = context.Request.RawUrl;  bool delCache = path.IndexOf("?del") > 0;  if (delCache)  {   path = path.Replace("?del", string.Empty);   DeleteCacheFile(path);   return;  }  bool allowCache = Request.QueryString["cache"] == "true";  string seconds = Request.QueryString["seconds"] ?? string.Empty;  if (!int.TryParse(seconds, out proxyCacheSeconds))  {   proxyCacheSeconds = 3600;  }  if (allowCache)  {   EchoData(path);  }  else  {   WebClient wc = new WebClient();   wc.Headers.Set("Referer", proxyReferer);   byte[] buffer = wc.DownloadData(proxyDomain + path);   Response.ContentType = wc.ResponseHeaders["Content-Type"];   foreach (string key in wc.ResponseHeaders.AllKeys)   {    Response.Headers.Set(key, wc.ResponseHeaders[key]);   }   wc.Dispose();   Response.OutputStream.Write(buffer, 0, buffer.Length);  } } /// <summary> /// 清理失效的緩存 /// </summary> /// <param name="d"></param> void ClearTimeoutCache(DirectoryInfo d) {  if (d.Exists)  {   FileInfo[] files = d.GetFiles();   foreach (FileInfo file in files)   {    TimeSpan timeSpan = DateTime.Now - file.LastAccessTime;    if (timeSpan.TotalSeconds > proxyCacheSeconds)    {     file.Delete();    }   }  } } string GetCacheFolderPath(string hash) {  string s = string.Empty;  for (int i = 0; i <= 2; i++)  {   s += hash[i] + "/";  }  return s; } /// <summary> /// 讀取緩存的header 并輸出 /// </summary> /// <param name="cacheHeaderPath"></param> void EchoCacheHeader(string cacheHeaderPath) {  string[] headers = File.ReadAllLines(cacheHeaderPath);  for (int i = 0; i < headers.Length; i++)  {   string[] headerKeyValue = headers[i].Split(':');   if (headerKeyValue.Length == 2)   {    if (headerKeyValue[0] == "Content-Type")    {     Response.ContentType = headerKeyValue[1];    }    Response.Headers.Set(headerKeyValue[0], headerKeyValue[1]);   }  } } void DeleteCacheFile(string path) {  string absFolder = Server.MapPath(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 (cacheBody.Exists)  {   cacheBody.Delete();  }  if (cacheHeader.Exists)  {   cacheHeader.Delete();  }  Response.Write("delete cache file Success!/r/n" + path); } /// <summary> /// 輸出緩存 /// </summary> /// <param name="cacheHeaderPath">緩存header 的文件路徑</param> /// <param name="cacheBodyPath">緩存 body 的文件路徑</param> /// <param name="ifTimeout">是否進行判斷文件過期</param> /// <returns>是否輸出成功</returns> bool EchoCacheFile(string cacheHeaderPath, string cacheBodyPath, bool ifTimeout) {  FileInfo cacheBody = new FileInfo(cacheBodyPath);  FileInfo cacheHeader = new FileInfo(cacheHeaderPath);  ClearTimeoutCache(cacheBody.Directory);  ClearTimeoutCache(cacheHeader.Directory);  if (cacheBody.Exists && cacheHeader.Exists)  {   if (ifTimeout)   {    TimeSpan timeSpan = DateTime.Now - cacheBody.LastWriteTime;    if (timeSpan.TotalSeconds < proxyCacheSeconds)    {     EchoCacheHeader(cacheHeaderPath);     Response.TransmitFile(cacheBodyPath);     return true;    }   }   else   {    EchoCacheHeader(cacheHeaderPath);    Response.TransmitFile(cacheBodyPath);    return true;   }  }  return false; } void EchoData(string path) {  string absFolder = Server.MapPath(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)   {    Response.Write("直接從緩存讀取失敗!");   }   return;  }  success = EchoCacheFile(cacheHeaderPath, cacheBodyPath, true);  if (success)  {   return;  }  //更新Cache File  string ApplicationKey = "CacheList";  List<string> List = null;  if (Application[ApplicationKey] == null)  {      Application.Lock();   Application[ApplicationKey] = List = new List<string>(1000);   Application.UnLock();  }  else  {   List = (List<string>)Application[ApplicationKey];  }  //判斷是否已有另一個進程正在更新Cache File  if (List.Contains(hash))  {   success = EchoCacheFile(cacheHeaderPath, cacheBodyPath, false);   if (success)   {    return;   }   else   {    WebClient wc = new WebClient();    wc.Headers.Set("Referer", proxyReferer);    //主體內容    byte[] data = wc.DownloadData(proxyDomain + path);    //處理header    Response.ContentType = wc.ResponseHeaders["Content-Type"];    foreach (string key in wc.ResponseHeaders.AllKeys)    {     Response.Headers.Set(key, wc.ResponseHeaders[key]);    }    wc.Dispose();    Response.BinaryWrite(data);   }  }  else  {   WebClient wc = new WebClient();   wc.Headers.Set("Referer", proxyReferer);   StringBuilder headersb = new StringBuilder();   List.Add(hash);   //主體內容   byte[] data = wc.DownloadData(proxyDomain + path);   //處理header   Response.ContentType = wc.ResponseHeaders["Content-Type"];   foreach (string key in wc.ResponseHeaders.AllKeys)   {    headersb.Append(key);    headersb.Append(":");    headersb.Append(wc.ResponseHeaders[key]);    headersb.Append("/r/n");    Response.Headers.Set(key, wc.ResponseHeaders[key]);   }   wc.Dispose();   string headers = headersb.ToString().Trim();   if (!Directory.Exists(absFolder + "/header/" + folder))   {    Directory.CreateDirectory(absFolder + "/header/" + folder);   }   StreamWriter sw = File.CreateText(absFolder + "/header/" + folder + hash);   sw.Write(headers);   sw.Close();   sw.Dispose();   //處理緩存內容   if (!Directory.Exists(absFolder + "/body/" + folder))   {    Directory.CreateDirectory(absFolder + "/body/" + folder);   }   FileStream fs = File.Create(absFolder + "/body/" + folder + hash);   fs.Write(data, 0, data.Length);   fs.Close();   fs.Dispose();   List.Remove(hash);   Response.BinaryWrite(data);  } } string GetHashString(string path) {  string md5 = GetMd5Str(path);  return md5; } static string GetMd5Str(string ConvertString) {  System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();  string t2 = BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)), 4, 8);  t2 = t2.Replace("-", "");  return t2; } public bool IsReusable {  get  {   return false;  } }}web.config文件如下:
<?xml version="1.0"?><configuration> <configSections> <section name="RewriterConfig" type="URLRewriter.Config.RewriterConfigSerializerSectionHandler, URLRewriter"/> </configSections> <RewriterConfig> <Rules> <RewriterRule> <LookFor>~/.*$</LookFor> <SendTo> <!--cache=true 設置此路徑進行緩存--> <![CDATA[~/proxy.ashx?cache=true&seconds=30]]> </SendTo> </RewriterRule> <RewriterRule> <LookFor>~/ajax/.*$</LookFor> <SendTo> <!--cache=false 設置此路徑不允許緩存--> <![CDATA[~/proxy.ashx?cache=false]]> </SendTo> </RewriterRule> </Rules> </RewriterConfig> <appSettings> <!--#反向代理設置 start--> <!--設置站點--> <add key="proxyDomain" value="http://127.0.0.1:12123/"/> <!--緩存文件夾--> <add key="proxyCacheFolder" value="/proxyCache/"/> <!--緩存時長--> <add key="proxyCacheSeconds" value="3600"/> <!--設置不再判斷緩存文件是否超時,直接從緩存讀取--> <add key="proxyCacheDirectAccess" value="false"/> <!--設置反向代理Referer--> <add key="proxyReferer" value="http://www.www.com/"/> <!--#反向代理設置 end--> </appSettings> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add type="URLRewriter.ModuleRewriter, URLRewriter" name="ModuleRewriter"/> </modules> </system.webServer> <system.web> <compilation debug="true"/> </system.web></configuration>
希望本文所述對大家的C#程序設計有所幫助。
新聞熱點
疑難解答