C#实现可缓存网页到本地的反向代理工具实例
程序员文章站
2022-04-11 08:01:57
本文实例讲述了c#实现可缓存网页到本地的反向代理工具。分享给大家供大家参考。具体实现方法如下:
proxy.ashx 主文件:
<%@ webhandle...
本文实例讲述了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#程序设计有所帮助。
上一篇: 多线程实战篇(二)