这一节我们来看一下DOTTEXT的TRACKBACK流程。
首先我们来看一下是怎么发送TRACKBACK的:入口是Dottext.Framework.EntryHandling.Process
- 检查文章内容中是否已经包含了远程网页的链接,只有包含才能继续
- 从远程链接的网页下载HTML代码,如果没得到,说明不是合法链接,要返回
- 在得到的HTML代码中检查是否已经包含了本文的链接,有说明已经PING过了,要返回
- 在得到的HTML代码中根据TRACKBACK标准取到要TRACKBACK链接(链接包含在RDF为键值的被注释的XHTML代码中),从而完成了由网页链接到TRACKBACK链接的转化
- 发送(PING)TRACKBACK。
再来看一下接收TRACKBACK的流程,入口是:Dottext.Framework.Tracking.TrackBackHandler.ProcessRequest
- 根据PING过来的TRACKBACK链接得到本地文章的ID号,得不到则不是合法链接,要返回
- REQUEST方法是否是POST,不是要返回,这是TRACKBACK标准规定的。
- 根据ID号从库中检索数据,生成ENTRY对象
- 根据传过来的URL下载远程网页的HTML代码,如果没得到或得到的HTML中没有包含本地文章的链接,说明不是合法链接,要返回
- 从得到的HTML代码中分析出对方的页面标题,如果没有,要返回
- 生成一个新的ENTRY对象,并对其各个属性赋值,然后入库
由此我们看到DOTTEXT发送TRACKBACK时效率是比较低的。原因是需要去下载远程的HTML,这将是一个非常耗时的工作,更不用说还要从很可能十分庞大的HTML代码中提取出TRACKBACK链接。
再者就是接收TRACKBACK时,并没有建立屏蔽机制。从而无法避免垃极广告的侵袭,也就是我们所说的SPAM COMMENT。
我想要解决这些问题,需要改变发送TRACKBACK的发送机制。
- 不再根据TRACKBACK标准去自动获取TRACKBACK,这样不仅效率极低,而且很多网站并不支持这个标准(比如www.blogchinese.com就直接提供引用通告,而不是隐藏在网页中,哈哈)的话,就无法TRACKBACK成功了。我们就认为用户输入的就是合法的TRACKBACK链接。直接进行发送。
- 为了能让用户得到合法的TRACKBACK地址,在每一篇文章内容之后,都显示此文的TRACKBACK链接。
- 再提供一个页面,输入网页链接,就能显示出此网页的TRACKBACK链接,以继续支持那些符合标准的网站
在接收TRACKBACK时,我们相应做以下改动:
- 将对方URL拿到库里去验证,看对方是否已经PING过了,因为是在本地进行,速度会非常快。
- 在库中建立BLACKIP表,对来方的IP进行校验,这样就拥有了封对方IP的功能。
以上只是我的设想,因为时间的原因,还没有动手去实现,如果大家有更好的建议,可以一起来探讨。
TRACKBACK是BLOG的一项重要功能,最近在到一些文章说TRACKBACK快要死了。我觉得TRACKBACK的最大障碍是标准问题。很多BLOG SITE并没有遵守TRACKBACK的标准,(标准的内容http://www.movabletype.org/docs/mttrackback.html)
在中国连http://www.blogchinese.com,http://www.bokee.com/这样的大型网站也没有遵守此标准,TRACKBACK应用不畅也是理所当然的了。
幸运的是DOTTEXT遵守了这一标准,相关类是:
Dottext.Framework.Tracking.TrackBackNotificationProxy:发送TRACKBACK
Dottext.Framework.Tracking.TrackBackHandler:接收PING过来的TRACKBAC
CNBlogsDottext10Beta2版本中,TRACKBACK功能被屏蔽掉了,原因可能是因为很多人安装成功后,在提交包含引用链接的POSTS时,出现错误:
将截断字符串或二进制数据
其实这是因为发送TRACKBACK的关键方法:SendPing(string trackBackItem, string parameters)里,发送字节流时按照ASCII码的长度来发送,当PARAMETERS中包含中文时,就会出错,解决方法是转换成UTF-8发送,下面是我修改过后的代码:
private void SendPing(string trackBackItem, string parameters)
{
HttpWebRequest request = BlogRequest.CreateRequest(trackBackItem);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.KeepAlive = false;
byte [] buff = Encoding.GetEncoding("UTF-8").GetBytes(parameters);
request.ContentLength = buff.Length;
Stream reqStream = null;
try
{
reqStream = request.GetRequestStream();
reqStream.Write(buff, 0, buff.Length);
}
catch(Exception e)
{
Logger.LogManager.CreateExceptionLog(e,"SendPing Exception");
}
finally
{
reqStream.Close();
}
下一节我将分析一下DOTTEXT在TRACKBACK时的流程,并对改善方法提供一些建议
这个方法,其实在DOTTEXT的一些ASCX文件里已经使用了,我们可以再根据自己的情况再增加或延长一些页面的缓存,如:
Syndication.ascx,首页聚合:缓存时间:3600
BlogList.ascx,博客排行:缓存时间:3600
SiteCategory.ascx,网站分类:缓存时间:3600
AggStats.ascx,首页的统计信息:缓存时间:3600。
还有其它一些,不再一一列举
下一节我将对TRACKBACK进行一些探讨
最近在开发博客,于是想到了OPENSOURCE的DOTTEXT,下载了装好后,感觉功能很完善,所以打算在其基础上建立BLOG SITE。感谢http://www.cnblogs.com/,我装的是CNBlogsDottext10Beta2版本。
我觉得一个BLOG SITE最重要的功能是:
1 换肤功能
2 RSS功能
3 TRACKBACK
在FIX、PERFORMANT以及LOCALIZATION过程中,感觉DOTTEXT的性能比较低,经分析后发现:
对于大量的访问CONFIG配置文件的操作,DOTTEXT并没有提供缓存机制。比如首页,大约有三十次访问BlogConfigurationSettings,而这全部都要执行以下代码:
{
return ((BlogConfigurationSettings)ConfigurationSettings.GetConfig("BlogConfigurationSettings"));
}
类似的还有 HTTP链接动态生成,每次都要由 UrlReWriteHandlerFactory 对REQUEST链接进行分析,这个过程要遍历HttpHandlers,而取得HttpHandlers要执行以下方法:
{
(UrlManager.HandlerConfiguration)ConfigurationSettings.GetConfig("HandlerConfiguration"); }
我们看到,每次访问配置项,都要从CONFIG文件中读取,而且每次都要进行装箱的操作。
为了解决以上问题,我在Dottext.Framework命名空间中建立了CATCHER类来缓存配置项。这是个单例类,代码如下:
using System.Configuration;
namespace Dottext.Framework
{
/// <summary>
/// 作者:丁冬
/// 时间:2006-02-24
/// 说明:将配置项缓存
/// </summary>
public class Catcher
{
private Catcher()
{
}
/// <summary>
/// 缓存BlogConfigurationSettings
/// </summary>
/// <returns></returns>
public static Configuration.BlogConfigurationSettings GetBlogConfigurationSettings()
{
if(_BlogConfigurationSettings == null)
_BlogConfigurationSettings = (Configuration.BlogConfigurationSettings)ConfigurationSettings.GetConfig("BlogConfigurationSettings");
}
}
}
相应的,将BlogConfigurationSettings 类的INSTANCE方法改为:
public static BlogConfigurationSettings Instance()
{
return Catcher.GetBlogConfigurationSettings();
}
这样,每次访问Dottext.Framework.Configuration.BlogConfigurationSettings Instance(),都先去缓存中提取,如果为NULL,则再去读配置文件。
同样的,我在Dottext.Common.UrlManager命名空间中也建立了一个CACHER类,来缓存HandlerConfiguration配置项。之所以不把他们放在一个CATCHER类里,是为了避免装箱操作。
优化后,我以首页为例进行优化前后的对比,结果如下:
Application Center Test
概述: 摘要
| (1) | 测试名称: | ACTSamples: 新BLOG |
| 测试运行名称: | report-新BLOG-二月 25, 2006 10-51-30 | |
| 测试开始时间: | 2006-2-25 10:50:28 | |
| 测试持续时间: | 00:00:01:00 | |
| 测试迭代次数: | 3,760 | |
| 测试说明: | - |
| (2) | 测试名称: | ACTSamples: 老Blog |
| 测试运行名称: | report-老Blog-二月 25, 2006 10-52-40 | |
| 测试开始时间: | 2006-2-25 10:51:38 | |
| 测试持续时间: | 00:00:01:00 | |
| 测试迭代次数: | 1,661 | |
| 测试说明: | - |
测试运行图形
显示错误
| 属性 | |||||
| (1) | (2) | ||||
| 测试类型: | 动态 | 动态 | |||
| 浏览器同时连接数: | 20 | 20 | |||
| 准备时间(秒): | |||||
| 测试持续时间: | 00:00:01:00 | 00:00:01:00 | |||
| 测试迭代次数: | 3,760 | 1,661 | |||
| 生成的详细测试结果: | 是 | 是 | |||
| 摘要 | |||||
| (1) | (2) | ||||
| 请求总数: | 3,762 | 1,663 | |||
| 连接总数: | 3,760 | 1,661 | |||
| 每秒平均请求数: | 62.70 | 27.72 | |||
| 首字节平均响应时间(毫秒): | 298.10 | 691.10 | |||
| 末字节平均响应时间(毫秒): | 299.60 | 693.47 | |||
| 每次迭代末字节平均响应时间(毫秒): | 299.76 | 694.30 | |||
| 测试中的唯一请求数: | 1 | 1 | |||
| 唯一响应代码数: | 1 | 1 | |||
| 错误计数 | |||||
| (1) | (2) | ||||
| HTTP: | |||||
| DNS: | |||||
| 套接字: | |||||
| 其他网络统计数据 | |||||
| (1) | (2) | ||||
| 平均带宽(字节/秒): | 1,182,812.80 | 510,220.68 | |||
| 发送字节数(字节): | 1,437,970 | 624,866 | |||
| 接收字节数(字节): | 69,530,798 | 29,988,375 | |||
| 发送字节平均速率(字节/秒): | 23,966.17 | 10,414.43 | |||
| 接收字节平均速率(字节/秒): | 1,158,846.63 | 499,806.25 | |||
| 连接错误数: | |||||
| 发送错误数: | |||||
| 接收错误数: | |||||
| 超时错误数: | |||||
| 响应代码 | |||||
| (1) | (2) | ||||
| Response Code: 200 - 请求已成功完成。 | |||||
| 计数: | 3,762 | 1,663 | |||
| 百分比(%): | 100.00 | 100.00 | |||
|
| |||||
可以看到,效率提高了2。3倍。
以上我缓存的只是访问比较频繁的两个配置项,我们可以将所有的配置都缓存。以使DOTTEXT性能达到最优。
