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#程序设计有所帮助。