C#实现可缓存网页到本地的反向代理工具实例

本文实例讲述了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#程序设计有所帮助。

(0)

相关推荐

  • 反向代理缓存的详细介绍

    反向代理缓存的详细介绍  传统代理: 用户隐藏在代理服务器之后.代理服务器工作在应用层,它只转发它支持的协议的数据.    反向代理(Reverse Proxy): 这种机制是Web服务器隐藏在代理服务器之后,实现这种机制的服务器称作反向代理服务器(Reverse Proxy Server).此时,Web服务器成为后端服务器,反向代理服务器称为前端服务器. 引入反向代理服务器的目的之一就是基于缓存的加速.我们可以将内容缓存在反向代理服务器上,所有缓存机制的实现仍然采用HTTP/1.1协议. 反向

  • linux下通过Squid反向代理搭建CDN缓存服务器的配置方法

    案例:Web服务器:域名www.abc.com IP:192.168.21.129 电信单线路接入访问用户:电信宽带用户.移动宽带用户出现问题:电信用户打开www.abc.com正常,移动用户打开www.abc.com很慢,甚至打不开解决方案:在移动机房放置一台CDN代理服务器,通过智能DNS解析,让电信用户直接访问Web服务器.让移动用户访问CDN代理服务器,解决移动用户访问Web服务器慢的问题具体操作:CDN代理服务器:系统:CentOS 5.5 主机名:cdn.abc.com IP:192

  • 使用Nginx反向代理与proxy_cache缓存搭建CDN服务器的配置方法

    碰到问题:移动用户访问web服务器www.osyunwei.com很慢解决办法:1.在移动机房放置一台nginx反向代理服务器2.通过域名DNS智能解析,所有移动用户访问www.osyunwei.com时解析到nginx反向代理服务器3.nginx反向代理服务器与web服务器之间采用专线连接说明:1.web服务器线路:电信IP:192.168.21.129域名:www.osyunwei.com2.nginx反向代理服务器线路:移动系统:CentOS 6.2IP:192.168.21.164vi

  • Nginx 反向代理并缓存及缓存清除的方法

    本文介绍了Nginx 反向代理并缓存及缓存清除的方法,分享给大家,具体如下: 一. Nginx 配置 #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { log_form

  • 详解Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解

    注,操作系统为 CentOS 6.4 x86_64 , Nginx 是版本是最新版的1.4.2,所以实验用到的软件请点击这里下载: CentOS 6.4下载地址:http://www.jb51.net/softs/78243.html Nginx下载地址:http://www.jb51.net/softs/35633.html 一.前言 在前面的几篇博文中我们主要讲解了Nginx作为Web服务器知识点,主要的知识点有nginx的理论详解.nginx作为web服务器的操作讲解.nginx作为LNM

  • ASP.NET 性能优化之反向代理缓存使用介绍

    到目前为止,我们讨论了把缓存存放在ASP.NET的输出缓存中(内存和硬盘),以及浏览器缓存中,而大型站点的另一种常用做法是将缓存部署在反向代理服务器上,这类缓存我们通常称之为反向代理缓存,比如Squid和Varnish.这两款软件通常都部署在非WINDOWS平台上,对于Windows平台上的Asp.net来说,其实一样能使用,我们完全可以把反向代理软件部署在LINUX上,然后代理会路由到后台的WINDOWS WEB(IIS)服务器.总之,非WINDOWS的世界很精彩. 当然,无论是squid还是

  • Nginx服务器作反向代理时的缓存配置要点解析

    这里给出示例,并详解. http { [...] [...] proxy_cache_path /data/nginx/cache/one levels=1:2 keys_zone=one:10m max_size=10g; proxy_cache_key "$host$request_uri"; server { server_name www.jb51.net jb51.net; root /home/www.jb51.net/web; index index.php index.

  • C#实现可缓存网页到本地的反向代理工具实例

    本文实例讲述了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;

  • swf和网页交互本地测试的注意事项

    注意是在本地测试 一.编码格式,如果是utf-8编码则直接打开页面内含有object对象时会提示是否加载控件,如果改为gb2312编码则没有提示 二,如果以gb2312编码的网页往页面中的swf对象传递参数中包含中文字符时,swf收到后需进行如下转码: var BA:ByteArray = new ByteArray; BA.writeMultiByte(value,"utf-8"); BA.position = 0; value=BA.readMultiByte(BA.length,

  • JS+ACTIVEX实现网页选择本地目录路径对话框

    网页选择本地目录路径对话框,使用ACTIVEX对象遍历本地磁盘和目录,只需网页启用相关ACTIVEX的INTERNET选项,对本地浏览器的安全性要求不高,简单易用.网页选择本地目录路径对话框样例 1.打开主页面"select.html",点击"选择路径"按钮进入路径选择页面"dir.html",选取本地目录路径 2.路径选择页面"dir.html"初始化后,加载本地磁盘驱动,然后根据选择的磁盘路径加载其中的目录.如目录中存在子

  • Android异步下载图片并且缓存图片到本地DEMO详解

    在Android开发中我们经常有这样的需求,从服务器上下载xml或者JSON类型的数据,其中包括一些图片资源,本demo模拟了这个需求,从网络上加载XML资源,其中包括图片,我们要做的解析XML里面的数据,并且把图片缓存到本地一个cache目录里面,并且用一个自定义的Adapter去填充到LIstView,demo运行效果见下图: 通过这个demo,要学会有一下几点 1.怎么解析一个XML 2.demo中用到的缓存图片到本地一个临时目录的思想是怎样的? 3.AsyncTask类的使用,因为要去异

  • javascript实现div浮动在网页最顶上并带关闭按钮效果实例

    复制代码 代码如下: <html> <head> <title>javascript实现div浮动在网页最顶上并带关闭按钮效果实例</title> <style type="text/css"> <!-- body { margin: 0px;padding: 0px;text-align: center;} TD {FONT-SIZE: 12px; COLOR: #333;} #toubiao {BORDER-BOTT

随机推荐