C#实现可缓存网页到本地的反向代理工具实例
本文实例讲述了C#实现可缓存网页到本地的反向代理工具。分享给大家供大家参考。具体实现方法如下:
proxy.ashx主文件:
<%@WebHandlerLanguage="C#"Class="proxy"%>
usingSystem;
usingSystem.Web;
usingSystem.Net;
usingSystem.Text;
usingSystem.IO;
usingSystem.Collections.Generic;
usingSystem.Configuration;
///<summary>
///把httpheaders和http响应的内容分别存储在/proxy/header/和/proxy/body/中
///分层次创建目录
///</summary>
publicclassproxy:IHttpHandler
{
HttpResponseResponse;
HttpRequestRequest;
HttpApplicationStateApplication;
HttpServerUtilityServer;
staticstringproxyCacheFolder=ConfigurationManager.AppSettings["proxyCacheFolder"];
staticstringproxyDomain=ConfigurationManager.AppSettings["proxyDomain"];
staticstringproxyReferer=ConfigurationManager.AppSettings["proxyReferer"];
boolproxyCacheDirectAccess=ConfigurationManager.AppSettings["proxyCacheDirectAccess"]=="true";
intproxyCacheSeconds=int.Parse(ConfigurationManager.AppSettings["proxyCacheSeconds"]);
publicvoidProcessRequest(HttpContextcontext)
{
Response=context.Response;
Request=context.Request;
Application=context.Application;
Server=context.Server;
stringpath=context.Request.RawUrl;
booldelCache=path.IndexOf("?del")>0;
if(delCache)
{
path=path.Replace("?del",string.Empty);
DeleteCacheFile(path);
return;
}
boolallowCache=Request.QueryString["cache"]=="true";
stringseconds=Request.QueryString["seconds"]??string.Empty;
if(!int.TryParse(seconds,outproxyCacheSeconds))
{
proxyCacheSeconds=3600;
}
if(allowCache)
{
EchoData(path);
}
else
{
WebClientwc=newWebClient();
wc.Headers.Set("Referer",proxyReferer);
byte[]buffer=wc.DownloadData(proxyDomain+path);
Response.ContentType=wc.ResponseHeaders["Content-Type"];
foreach(stringkeyinwc.ResponseHeaders.AllKeys)
{
Response.Headers.Set(key,wc.ResponseHeaders[key]);
}
wc.Dispose();
Response.OutputStream.Write(buffer,0,buffer.Length);
}
}
///<summary>
///清理失效的缓存
///</summary>
///<paramname="d"></param>
voidClearTimeoutCache(DirectoryInfod)
{
if(d.Exists)
{
FileInfo[]files=d.GetFiles();
foreach(FileInfofileinfiles)
{
TimeSpantimeSpan=DateTime.Now-file.LastAccessTime;
if(timeSpan.TotalSeconds>proxyCacheSeconds)
{
file.Delete();
}
}
}
}
stringGetCacheFolderPath(stringhash)
{
strings=string.Empty;
for(inti=0;i<=2;i++)
{
s+=hash[i]+"/";
}
returns;
}
///<summary>
///读取缓存的header并输出
///</summary>
///<paramname="cacheHeaderPath"></param>
voidEchoCacheHeader(stringcacheHeaderPath)
{
string[]headers=File.ReadAllLines(cacheHeaderPath);
for(inti=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]);
}
}
}
voidDeleteCacheFile(stringpath)
{
stringabsFolder=Server.MapPath(proxyCacheFolder);
stringhash=GetHashString(path);
stringfolder=GetCacheFolderPath(hash);
stringcacheBodyPath=absFolder+"/body/"+folder+hash;
stringcacheHeaderPath=absFolder+"/header/"+folder+hash;
FileInfocacheBody=newFileInfo(cacheBodyPath);
FileInfocacheHeader=newFileInfo(cacheHeaderPath);
if(cacheBody.Exists)
{
cacheBody.Delete();
}
if(cacheHeader.Exists)
{
cacheHeader.Delete();
}
Response.Write("deletecachefileSuccess!\r\n"+path);
}
///<summary>
///输出缓存
///</summary>
///<paramname="cacheHeaderPath">缓存header的文件路径</param>
///<paramname="cacheBodyPath">缓存body的文件路径</param>
///<paramname="ifTimeout">是否进行判断文件过期</param>
///<returns>是否输出成功</returns>
boolEchoCacheFile(stringcacheHeaderPath,stringcacheBodyPath,boolifTimeout)
{
FileInfocacheBody=newFileInfo(cacheBodyPath);
FileInfocacheHeader=newFileInfo(cacheHeaderPath);
ClearTimeoutCache(cacheBody.Directory);
ClearTimeoutCache(cacheHeader.Directory);
if(cacheBody.Exists&&cacheHeader.Exists)
{
if(ifTimeout)
{
TimeSpantimeSpan=DateTime.Now-cacheBody.LastWriteTime;
if(timeSpan.TotalSeconds<proxyCacheSeconds)
{
EchoCacheHeader(cacheHeaderPath);
Response.TransmitFile(cacheBodyPath);
returntrue;
}
}
else
{
EchoCacheHeader(cacheHeaderPath);
Response.TransmitFile(cacheBodyPath);
returntrue;
}
}
returnfalse;
}
voidEchoData(stringpath)
{
stringabsFolder=Server.MapPath(proxyCacheFolder);
stringhash=GetHashString(path);
stringfolder=GetCacheFolderPath(hash);
stringcacheBodyPath=absFolder+"/body/"+folder+hash;
stringcacheHeaderPath=absFolder+"/header/"+folder+hash;
boolsuccess;
if(proxyCacheDirectAccess)
{
success=EchoCacheFile(cacheHeaderPath,cacheBodyPath,false);
if(!success)
{
Response.Write("直接从缓存读取失败!");
}
return;
}
success=EchoCacheFile(cacheHeaderPath,cacheBodyPath,true);
if(success)
{
return;
}
//更新CacheFile
stringApplicationKey="CacheList";
List<string>List=null;
if(Application[ApplicationKey]==null)
{
Application.Lock();
Application[ApplicationKey]=List=newList<string>(1000);
Application.UnLock();
}
else
{
List=(List<string>)Application[ApplicationKey];
}
//判断是否已有另一个进程正在更新CacheFile
if(List.Contains(hash))
{
success=EchoCacheFile(cacheHeaderPath,cacheBodyPath,false);
if(success)
{
return;
}
else
{
WebClientwc=newWebClient();
wc.Headers.Set("Referer",proxyReferer);
//主体内容
byte[]data=wc.DownloadData(proxyDomain+path);
//处理header
Response.ContentType=wc.ResponseHeaders["Content-Type"];
foreach(stringkeyinwc.ResponseHeaders.AllKeys)
{
Response.Headers.Set(key,wc.ResponseHeaders[key]);
}
wc.Dispose();
Response.BinaryWrite(data);
}
}
else
{
WebClientwc=newWebClient();
wc.Headers.Set("Referer",proxyReferer);
StringBuilderheadersb=newStringBuilder();
List.Add(hash);
//主体内容
byte[]data=wc.DownloadData(proxyDomain+path);
//处理header
Response.ContentType=wc.ResponseHeaders["Content-Type"];
foreach(stringkeyinwc.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();
stringheaders=headersb.ToString().Trim();
if(!Directory.Exists(absFolder+"/header/"+folder))
{
Directory.CreateDirectory(absFolder+"/header/"+folder);
}
StreamWritersw=File.CreateText(absFolder+"/header/"+folder+hash);
sw.Write(headers);
sw.Close();
sw.Dispose();
//处理缓存内容
if(!Directory.Exists(absFolder+"/body/"+folder))
{
Directory.CreateDirectory(absFolder+"/body/"+folder);
}
FileStreamfs=File.Create(absFolder+"/body/"+folder+hash);
fs.Write(data,0,data.Length);
fs.Close();
fs.Dispose();
List.Remove(hash);
Response.BinaryWrite(data);
}
}
stringGetHashString(stringpath)
{
stringmd5=GetMd5Str(path);
returnmd5;
}
staticstringGetMd5Str(stringConvertString)
{
System.Security.Cryptography.MD5CryptoServiceProvidermd5=newSystem.Security.Cryptography.MD5CryptoServiceProvider();
stringt2=BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(ConvertString)),4,8);
t2=t2.Replace("-","");
returnt2;
}
publicboolIsReusable
{
get
{
returnfalse;
}
}
}
web.config文件如下:
<?xmlversion="1.0"?> <configuration> <configSections> <sectionname="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--> <!--设置站点--> <addkey="proxyDomain"value="http://127.0.0.1:12123/"/> <!--缓存文件夹--> <addkey="proxyCacheFolder"value="/proxyCache/"/> <!--缓存时长--> <addkey="proxyCacheSeconds"value="3600"/> <!--设置不再判断缓存文件是否超时,直接从缓存读取--> <addkey="proxyCacheDirectAccess"value="false"/> <!--设置反向代理Referer--> <addkey="proxyReferer"value="http://www.www.com/"/> <!--#反向代理设置end--> </appSettings> <system.webServer> <modulesrunAllManagedModulesForAllRequests="true"> <addtype="URLRewriter.ModuleRewriter,URLRewriter"name="ModuleRewriter"/> </modules> </system.webServer> <system.web> <compilationdebug="true"/> </system.web> </configuration>
希望本文所述对大家的C#程序设计有所帮助。