Archive

Posts Tagged ‘AJAX’

在线拍卖系统

September 30th, 2009 Bali 1 comment

早上,习惯性地打开新浪,小心地在广告链接中穿行,点新闻看。一则关于淘宝一元秒杀的新闻,很有意思。故事大概是:9/25日晚8时,淘宝将价值数千元的商品,以一元标价在淘宝上拍卖,庆祝成立6周年。结果搞砸了。很多用户还未看到开始页面就结束了,还有人用作弊器同时拍到了多个商品。

此事从商务角度来说,淘宝是毫无疑问的赢家。此次拍卖的目的并非真的拍卖,而是赚人气,赚眼球。尚不清楚,淘宝是否真的故意造成争议话题,让大家去议论,正如电影拍摄中常常传出男女主角的桃色新闻一样。从技术角度来说,如果要较完善设计此系统的话,至少有几点值得商榷。

(1)Use server push instead of client pull. 有淘宝用户留言,

我从19:50开始,不断刷新页面,都是显示“即将开始”,再刷新,活动已经结束!MLGB…

在线拍卖讲究的就是时效性,大家都想以最低的价格得到某样商品,所以非常想知道最新的价格,这时候就疯狂刷页面,造成服务器压力很大。另外一种做法是Server Push, “你们都不要刷了,有消息会告诉你们的,回家等着吧。” 这种东东就叫做Server Push。也不是什么新的概念,用Java applet等插件N年前都能实现,但让每个人都装这么个插件显然代价太大。现在的SilverLight, Flex也能实现类似功能,但需要安装插件。Dojo的Comet很好地解决了这个问题。code在这里。不用装插件,可以穿越防火墙,而且scalability很好,也可以做cluster。淘宝的兄弟们真应该考虑一下这个东西。对Java天然支持。很可能将是Servlet 3.0的一部分,HTML5中也有类似的概念了。Server Push的应用范围主要在Server需要主动传递信息给client的情况,如在线拍卖,聊天,股票报价等。下面是一个介绍的slide,有兴趣的朋友,仔细看看。5分钟就可以用maven弄一个玩玩。

(2)用一点anti-spamming技术吧,在这里就是验证码(CAPTCHA)。只有人能拍,程序不能拍。

(3)防一下DoS攻击,把疯狂刷页面的同学的IP暂时放入黑名单,或者弹出一个验证码页面。

Designing Your Own Recent Posts Widget for MSDN Blog

July 29th, 2009 Bali 1 comment

In my MSDN blog, I need “Recent Posts”, but I don’t need archive side bar. After having played with template for a while, still no luck. Hmmm, looks like I have to DIY it. Fortunately in News sidebar, you can fill in raw html including JavaScript. Then next question is where we can retrieve post tiles. The immediate idea is from current DOM document. Through experiments, I found this is impossible because the DOM is not fully loaded yet when the script is executed. Later, I figured it out that all posts title can be gotten from RSS. For my blog, the address is http://blogs.msdn.com/bali_msft/rss.xml. One thing worth noticing is the fact that RSS in MSDN blog is not up to date – Your post will not instantly appear in the RSS. After I get all posts in RSS format, things became much easier. And then I go ahead to add more interesting things:

  • Posts background use two colors in turn
  • Show a new tag for posts less than 3 days old
  • Show latest 8 posts only
  • Show posts’ age

So, the final thing will look like this:

If you find it is useful, feel free to paste below code to you blog’s news section. Note to customize “Configurable params” to your own needs and leave other code intact. It works well at least in my IE 8 and Firefox 3.0.6.

<div id=”RecentPosts”></div>

<Script>

// Configurable params

var recentPostNumber = 8;

var rssUrl = “http://blogs.msdn.com/bali_msft/rss.xml”;

var title = “My Recent Posts”;

var newPostAgeInHour = 72;

// Cacluate age of one post. It is all about getting time span in Javascript

// return formate: x min; x hour y min, x day y min, x days, x yeas (ago)

// Refer to: http://www.w3schools.com/jsref/jsref_obj_date.asp

function calculateAge(postDate)

{

var ret = “fresh!”;

CurrentDate = new Date();

TimeSpan = new Date(CurrentDate – postDate);

var mySpanArray = new Array();

mySpanArray[0] = TimeSpan.getUTCFullYear()-1970;
mySpanArray[1] = TimeSpan.getUTCMonth();
mySpanArray[2] = TimeSpan.getUTCDate()-1;
mySpanArray[3] = TimeSpan.getUTCHours();
mySpanArray[4] = TimeSpan.getUTCMinutes();

var TimeSpanTagArray_1 = new Array(“years”, “months”, “days”, “hours”, “minutes”);

var TimeSpanTagArray_2 = new Array(“year”, “month”, “day”, “hour”, “minute”);

// Starting from non-zero element and pick two significant values

for(i = 0; i < mySpanArray.length; i++) {

if(mySpanArray[i] != 0) {

var correctTag = (mySpanArray[i] == 1)?(TimeSpanTagArray_2[i]):(TimeSpanTagArray_1[i]);

ret = mySpanArray[i] + ” “ + correctTag;

if(i+1 < mySpanArray.length && mySpanArray[i+1] != 0) {

correctTag = (mySpanArray[i+1] == 1)?(TimeSpanTagArray_2[i+1]):(TimeSpanTagArray_1[i+1]);

ret = ret + “, “ + mySpanArray[i+1] + ” “ + correctTag;

}

break;

}

}

return ret;

}

// Display the recent posts

// Refer to:

// http://www.w3schools.com/DOM/dom_node.asp

// http://www.w3schools.com/DOM/dom_methods.asp

function displayPosts (xmldoc)

{

var newTag = “<SPAN style=\”COLOR: red\”>(New!)</SPAN>”;

var posts = xmldoc.getElementsByTagName(“item”);

var displayText = “<h3>” + title + “</h3><UL>”;

if (posts.length < recentPostNumber) {

recentPostNumber = posts.length;

}

for(var i = 0; i < recentPostNumber; i++)

{

PostTitle = posts[i].firstChild.firstChild.nodeValue;

PostLink = posts[i].firstChild.nextSibling.firstChild.nodeValue;

PostDateStr = posts[i].firstChild.nextSibling.nextSibling.firstChild.nodeValue;

PostDate = new Date(PostDateStr);

CurrentDate = new Date();

// Calculate age

var _PostAge = calculateAge(PostDate);

var PostAge = “<SPAN style=\”font-size: 80%; color: black\”> (“ +_PostAge + ” ago)</SPAN>”;

// Show a new tag for posts happening last days defined by ‘newPostAgeInHour’

var myNewTag = “”;

if((CurrentDate.getTime() – PostDate.getTime())/1000/60 < newPostAgeInHour * 60) {

myNewTag = newTag;

}

// Get background color

var BKColor = (i%2 == 0)?(“#B8CCE4″):(“#DBE5F1″);

displayText = displayText + “<LI style=\”background-color:” + BKColor + “\”><A href=\”" + PostLink + “\”>” + myNewTag + PostTitle + PostAge + “</A></LI>”

}

displayText = displayText + “</UL>”;

var target = document.getElementById(“RecentPosts”);

target.innerHTML=displayText;

}

// Call back

function complete(){

if (req.readyState == 4) {

if (req.status == 200) {

displayPosts (req.responseXML);

}

}

}

// Initial async call

function getPosts()

{

if (window.XMLHttpRequest) {

req = new XMLHttpRequest();

}else if (window.ActiveXObject) {

req = new ActiveXObject(“Microsoft.XMLHTTP”);

}

if(req){

req.open(“GET”, rssUrl, true);

req.onreadystatechange = complete;

req.send(null);

}

}

// Entry point

getPosts();

</Script>