<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Lync.in &#187; Web Development</title>
	<atom:link href="http://lync.in/category/tech/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://lync.in</link>
	<description>Link the world.</description>
	<lastBuildDate>Thu, 19 Jan 2012 09:41:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>在 JavaScript 中判断“空值”</title>
		<link>http://lync.in/check-empty-value-in-javascript/</link>
		<comments>http://lync.in/check-empty-value-in-javascript/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 15:49:23 +0000</pubDate>
		<dc:creator>Justice</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[data type]]></category>
		<category><![CDATA[empty value]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[toString]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1718</guid>
		<description><![CDATA[本文作者：Justice有时候我们会遇到这样的情况：在一些前端控件要提交数据到服务器端的数据验证过程中，需要判断提交的数据是否为空。如果是普通表单的字符串数据，只需要在 trim 后判断 length 即可，而这里需要的数据可以是各种不同的类型(数字、字符串、数组、对象等等)，通过 JSON.stringify(data) 进行序列化后再传递。 在这里定义如下的数据值为“空值”： undefined null 空字符串及纯空白字符串：''、'&#160;&#160;&#160;&#160;' 等。 空数组：[] 空对象：{} 对于除此以外的数据值，均认为不为空。 其中 null 和 undefined 很容易识别，但对于其他类型，我们须要得到其数据类型才能用相应的方法去检测数据是否为空。最容易想到的方法就是利用 typeof 操作符： JavaScript1 2 3 if&#40;typeof data === 'number'&#41; &#123; //deal with numbers &#125; 但 typeof 返回的类型字符串只有 'object'、'function'、'number'、'boolean'、'string'、'undefined' 这六种，很多原生对象如 Date、RegExp 对象无法与用 {} 创建的对象进行区分。另外，typeof 对于一些基本数据类型如 (String、Number、Boolean) 与其对应的基本包装类型数据会分别返回不同值，如： JavaScript1 2 3 4 5 6 console.log&#40;typeof false&#41;; //'boolean' [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/1/" title="Posts by Justice">Justice</a></div><p>有时候我们会遇到这样的情况：在一些前端控件要提交数据到服务器端的数据验证过程中，需要判断提交的数据是否为空。如果是普通表单的字符串数据，只需要在 <code>trim</code> 后判断 <code>length</code> 即可，而这里需要的数据可以是各种不同的类型(数字、字符串、数组、对象等等)，通过 <code>JSON.stringify(<var>data</var>)</code> 进行序列化后再传递。</p>
<p>在这里定义如下的数据值为“空值”：</p>
<ul>
<li>undefined</li>
<li>null</li>
<li>空字符串及纯空白字符串：''、'&nbsp;&nbsp;&nbsp;&nbsp;' 等。</li>
<li>空数组：[]</li>
<li>空对象：{}</li>
</ul>
<p>对于除此以外的数据值，均认为不为空。</p>
<p><span id="more-1718"></span>其中 <code>null</code> 和 <code>undefined</code> 很容易识别，但对于其他类型，我们须要得到其数据类型才能用相应的方法去检测数据是否为空。最容易想到的方法就是利用 <code>typeof</code> 操作符：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #3D9EDD;">if</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> data <span style="color: #CCC;">===</span> <span style="color: #7ACC00;">'number'</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
  <span style="color: #999;">//deal with numbers</span>
<span style="color: #CCC;">&#125;</span></pre></td></tr></table></div></div>

<p>但 <code>typeof</code> 返回的类型字符串只有 'object'、'function'、'number'、'boolean'、'string'、'undefined' 这六种，很多原生对象如 Date、RegExp 对象无法与用 {} 创建的对象进行区分。另外，<code>typeof</code> 对于一些基本数据类型如 (String、Number、Boolean) 与其对应的基本包装类型数据会分别返回不同值，如：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #F2B646;">false</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'boolean'</span>
console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #F2B646;">new</span> Boolean<span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">false</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'object'</span>
console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #FFCC00;">1</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'number'</span>
console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #F2B646;">new</span> Number<span style="color: #CCC;">&#40;</span><span style="color: #FFCC00;">1</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'object'</span>
console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #7ACC00;">''</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'string'</span>
console.<span style="color: #FFF;">log</span><span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">typeof</span> <span style="color: #F2B646;">new</span> String<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">''</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//'object'</span></pre></td></tr></table></div></div>

<p>这对我们的判断也有一定的影响。</p>
<p>用 <code>instanceof</code>？这只能判断对象，而且存在<a href="https://developer.mozilla.org/en/JavaScript/Reference/Operators/instanceof#section_5" title="instanceof and multiple context">多 frame 时多个同类对象不共享 prototype</a> 的问题，从其他 frame 中取得的对象无法正确判断。</p>
<p>还好，还有一个最简单也最可靠的方法：<code>Object.prototype.toString</code>。对于不同类型的数据，这个方法可以返回 '[object Object]'、'[object Array]'、'[object String]' 这样的字符串，非常方便判断。需要注意的是，在 IE8 及其以下浏览器中，这个方法对于 <code>null</code>、<code>undefined</code>、<code>window</code> 等都会返回 '[object Object]'，不过还好，这并不影响我们使用它判断空对象。</p>
<p>下面直接上代码，说明就看注释吧。</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #999;">// with jQuery</span>
<span style="color: #F2B646;">var</span> isEmptyValue <span style="color: #CCC;">=</span> <span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span>value<span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    <span style="color: #F2B646;">var</span> type<span style="color: #CCC;">;</span>
    <span style="color: #3D9EDD;">if</span><span style="color: #CCC;">&#40;</span>value <span style="color: #CCC;">==</span> <span style="color: #F2B646;">null</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span> <span style="color: #999;">// 等同于 value === undefined || value === null</span>
        <span style="color: #3D9EDD;">return</span> <span style="color: #F2B646;">true</span><span style="color: #CCC;">;</span>
    <span style="color: #CCC;">&#125;</span>
    type <span style="color: #CCC;">=</span> Object.<span style="color: #FFF;">prototype</span>.<span style="color: #FFF;">toString</span>.<span style="color: #FFF;">call</span><span style="color: #CCC;">&#40;</span>value<span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">slice</span><span style="color: #CCC;">&#40;</span><span style="color: #FFCC00;">8</span><span style="color: #CCC;">,</span> <span style="color: #CCC;">-</span><span style="color: #FFCC00;">1</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    <span style="color: #3D9EDD;">switch</span><span style="color: #CCC;">&#40;</span>type<span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
        <span style="color: #3D9EDD;">case</span> <span style="color: #7ACC00;">'String'</span><span style="color: #CCC;">:</span>
            <span style="color: #3D9EDD;">return</span> <span style="color: #CCC;">!!</span>$.<span style="color: #FFF;">trim</span><span style="color: #CCC;">&#40;</span>value<span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
        <span style="color: #3D9EDD;">case</span> <span style="color: #7ACC00;">'Array'</span><span style="color: #CCC;">:</span>
            <span style="color: #3D9EDD;">return</span> <span style="color: #CCC;">!</span>value.<span style="color: #FFF;">length</span><span style="color: #CCC;">;</span>
        <span style="color: #3D9EDD;">case</span> <span style="color: #7ACC00;">'Object'</span><span style="color: #CCC;">:</span>
            <span style="color: #3D9EDD;">return</span> $.<span style="color: #FFF;">isEmptyObject</span><span style="color: #CCC;">&#40;</span>value<span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">// 普通对象使用 for...in 判断，有 key 即为 false</span>
        <span style="color: #F2B646;">default</span><span style="color: #CCC;">:</span>
            <span style="color: #3D9EDD;">return</span> <span style="color: #F2B646;">false</span><span style="color: #CCC;">;</span> <span style="color: #999;">// 其他对象均视作非空</span>
    <span style="color: #CCC;">&#125;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">;</span></pre></td></tr></table></div></div>

<p>对于不同 <code>value</code> 值，我做了个测试，看看对于不同值分别取 <code>Object.prototype.toString</code>、<code>typeof</code>、<code>isEmpty</code> 的结果。测试结果可以到下面这个地址围观：<br />
<a href="http://jsfiddle.net/Justineo/hFKRt/" title="isEmpty Test">http://jsfiddle.net/Justineo/hFKRt/</a></p>
<p>除了 IE8 及其以下浏览器外，其他浏览器结果基本一致，下面就贴下主要的 2 种结果吧。下图为 Firefox 下的结果，而在 Chrome 下，<code>window</code> 字符串化后的结果是 'object global'，和 Firefox 下稍有不同，但在判断空值时问题不大。<br />
<div id="attachment_1746" class="wp-caption aligncenter" style="width: 509px"><img src="http://lync.in/wp-content/uploads/2011/12/isempty-fx.png" alt="Firefox" title="isempty-fx" width="499" height="505" class="size-full wp-image-1746" /><p class="wp-caption-text">Firefox 下的结果</p></div></p>
<p>IE8 及以下唯一会误判的是 <code>alert</code>，不过这对于数据验证来说应该也可以接受。<br />
<div id="attachment_1752" class="wp-caption aligncenter" style="width: 509px"><img src="http://lync.in/wp-content/uploads/2011/12/isempty-ie.png" alt="IE8-" title="isempty-ie" width="499" height="505" class="size-full wp-image-1752" /><p class="wp-caption-text">IE8 及以下的结果</p></div></p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/check-empty-value-in-javascript/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/check-empty-value-in-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Firefox下用Flash上传文件的session陷阱</title>
		<link>http://lync.in/session-trap-on-uploading-files-using-flash-in-firefox/</link>
		<comments>http://lync.in/session-trap-on-uploading-files-using-flash-in-firefox/#comments</comments>
		<pubDate>Sat, 29 Oct 2011 10:47:17 +0000</pubDate>
		<dc:creator>Justice</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[cookie]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[SWFUpload]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1659</guid>
		<description><![CDATA[本文作者：Justice这几天在项目中遇到的问题，稍微整理一下。 HTML 表单是我们常用来进行浏览器与服务器数据交互的途径，除了传递普通的文本数据，通过 type="file" 的 input 控件，我们还可以向服务器发送文件。但在目前的实际使用中，基于 HTML 表单的文件选择框有着下面两个不尽人意之处： 一次只能选择一个文件 上传过程中，不能获取文件上传的进度 对于文件选择的数量，事实上在 HTML4.01 规范中对文件选择框的描述虽然没有明确提出可以同时选择多个文件，但从其用词可以看出，文件选择控件事实上是应该支持同时选择多个文件的： This control type allows the user to select files so that their contents may be submitted with a form. The INPUT element is used to create a file select control. 可以看见，“文件”一词使用的是复数形式。同时，RFC 1867: Form-based File Upload in HTML 的 3.3 节中，也有这样的描述： If [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/1/" title="Posts by Justice">Justice</a></div><p>这几天在项目中遇到的问题，稍微整理一下。</p>
<p><abbr title="Hypertext Markup Language">HTML</abbr> 表单是我们常用来进行浏览器与服务器数据交互的途径，除了传递普通的文本数据，通过 <code>type="file"</code> 的 input 控件，我们还可以向服务器发送文件。但在目前的实际使用中，基于 HTML 表单的文件选择框有着下面两个不尽人意之处：</p>
<ol>
<li>一次只能选择一个文件</li>
<li>上传过程中，不能获取文件上传的进度</li>
</ol>
<p>对于文件选择的数量，事实上在 <a href="http://www.w3.org/TR/html401/interact/forms.html#file-select" title="File Select">HTML4.01 规范</a>中对文件选择框的描述虽然没有明确提出可以同时选择多个文件，但从其用词可以看出，文件选择控件事实上是<em>应该</em>支持同时选择多个文件的：<span id="more-1659"></span></p>
<blockquote><p>
This control type allows the user to select <em>files</em> so that their contents may be submitted with a form. The INPUT element is used to create a file select control.
</p></blockquote>
<p>可以看见，“文件”一词使用的是复数形式。同时，<a href="http://tools.ietf.org/html/rfc1867" title="Form-based File Upload in HTML">RFC 1867: Form-based File Upload in HTML</a> 的 3.3 节中，也有这样的描述：</p>
<blockquote><p>
If multiple files are selected, they should be transferred together using the multipart/mixed format.
</p></blockquote>
<p>说明文件选择框应当能够处理同时选择多个文件的情况。但需要注意的是，这个描述出现在这篇规范文档的 3. Suggested implementation 章节中，仅仅是建议的实现方式，所以除了以前有几个版本的 <a href="http://www.cs.tut.fi/~jkorpela/forms/file.html#opera" title="Opera Support for File Input">Opera</a> 曾经支持过多文件选择，其余浏览器都仅仅实现了单个文件的选择功能。</p>
<p>为了解决这个问题，HTML5 中进行了<a href="http://www.w3.org/TR/html5/common-input-element-attributes.html#attr-input-multiple" title="The multiple attribute">明确</a>，带有 <code>multiple</code> 属性的 input 控件将可以有多个取值，自然也包括文件选择框。但这不是今天说的重点，目前的困境还是摆在我们眼前的。</p>
<p>对于文件上传的进度，就更不好办了：一是文件上传本身就无法使用 AJAX 来进行页内无刷新上传，需要使用隐藏 iframe 来实现。而获取上传进度还得依靠 AJAX 向服务器端发送请求来获取，利用的手段可以是 AJAX 轮询、iframe + htmlfile 甚至是 WebSocket，但本质上做的事情都有违常理：浏览器自己发送了多少内容，却需要一遍遍地请求服务器来进行告知。其次，由于文件上传和进度查询采用的是不同的数据通道，还得使用额外数据来维护两者之间的联系，显得非常繁复。</p>
<p>好了，说了那么一大段就是为了引出目前使用 Flash 来进行文件上传的原因。目前我们项目采用的是 <a href="http://swfupload.org/" title="SWFUpload">SWFUpload</a> 这个 Flash 文件上传工具，支持文件批量选择，并且可以方便地进行上传进度的查询。但是在我们的项目的之前版本中，当页面需要使用 session 中的用户信息时，却无法在 Firefox 下使用它进行正常的文件上传。</p>
<p>在 IE 下，上传工具能够工作，而一到 Firefox 下，SWFUpload 就会提示错误 302。通过从 Fiddler 抓包，发现上传文件的请求被 302 重定向到了登陆页面，所以无法正常上传文件。也就是说，之前用户登陆后的 session 信息在 Flash 发送的上传请求中丢失了。再一看请求的 header，当中没有可以用来标识当前 session ID 的 cookie 值(对于 J2EE 为 JSESSIONID，PHP 为 PHPSESSID 等)。这是什么原因呢？经过一番搜索，找到了 Adobe 官方的<a href="http://cookbooks.adobe.com/post_Why_is_session_info__cookies__not_sent_when_upload-12029.html" title="Why is session info (cookies) not sent when uploading files in Firefox?">一篇文章</a>，说道：</p>
<blockquote><p>
A FileReference.upload() currently does not use the same cookies as your browser session if you are using Firefox (on Windows). In such cases, cookie information has to be inserted manually.
</p></blockquote>
<p>好吧，这个解释虽然很清楚地表明，Flash 在 Firefox 下进行文件上传不会使用浏览器 cookie 中的 session ID，但是貌似并没有回答文章标题当中的“为什么”，即为什么不使用和浏览器中的 session ID 来进行通信。</p>
<p>看来 cookie 是指望不上了，那只能像上面说的那样“手工”传递 session ID 了。于是我们可以在 URL 中拼接一个如 <code>";jsessionid=blahblah"</code> 的字符串(注意要拼在路径之后，参数之前)，像下面这样：</p>
<blockquote><p>http://example.com/app;jsessionid=blahblah?q=blah</p></blockquote>
<p>按<a href="http://download.oracle.com/otndocs/jcp/servlet-2.4-fr-spec-oth-JSpec/" title="Java™ Servlet Specification Version 2.4">Servlet 规范</a> 7.1.3 节中的规定，当客户端不接受 cookie 时，Servlet 容器应当能解析出这类 URL 中的 JSESSIONID，来维持当前 session 的状态。其他服务器端环境中也有类似的机制。于是我们对文件上传功能做了一定的修改：在用户进入上传页面时，就把当前的 session ID 写到页面中，作为 JavaScript 变量拼接到 SWFUpload 上传文件的目标 URL 中，Flash 就可以利用我们人工传入的 JSESSIONID 来维持登陆状态了。当开始上传时，Flash 通过自己的连接通道向服务器发送数据，但是因为请求的路径中包含了 session 信息所以可以和浏览器的 session 状态保持同步，服务器可以通过 URL 中的 session ID 来获取用户登录的信息。</p>
<p>于是，302 错误被解决了，看起来一切都 OK 了。可是，不久我们又发现了新的问题：当用户打开上传页面后较长时间没有操作，服务器端的 session 超时了，这个时候进行文件的上传用的还是超时的那个 session ID，所以会失败也是应该的。但是当这个时候用户重新进行了登录，再次进入上传页面上传，却仍然会失败，只有重新启动浏览器才能再次进行上传。这是为什么呢？从服务器端错误来看，还是用户的登陆信息丢失的问题，也就是说，Flash 在上传文件时，还是没能将用户进行过登陆的这个 session ID 成功传递给服务器端。通过在 Fiddler 中抓包分析，终于找到了原因。下面几张示意图大致描述了这个问题产生的过程：<br />
<img src="http://lync.in/wp-content/uploads/2011/10/first.png" alt="First Flash Request" title="First Flash Request" width="500" height="200" class="aligncenter size-full wp-image-1667" />登陆后 Flash 第一次进行上传时，自身没有 JSESSIONID 这个 Cookie，所以使用手工拼接到请求 URL 中的浏览器 JSESSIONID 即 XXX 进行提交，服务器解析出了 JSESSIONID 并且在内存中找到了其对应的 session 信息，成功进行了身份验证，最后返回上传成功的信息。</p>
<p><img src="http://lync.in/wp-content/uploads/2011/10/second.png" alt="Second Flash Request" title="Second Flash Request" width="500" height="200" class="aligncenter size-medium wp-image-1668" />然而当 XXX 这个 session ID 超时以后，Flash 仍然以刚才重写过的 URL 发送请求(图中[1])，服务器解析出 JSESSIONID 后发现已经没有 XXX 这个 session 了，于是重新创建了一个 ID 为 YYY 的 session(图中[2])，并且在返回的响应中除了登陆失败的信息外还加入了 SET-COOKIE:JSESSIONID=YYY 的请求头(图中[3])。于是这时在 Flash 的 <acronym title="Local Shared Objects">LSO</acronym> (“Flash cookies”) 中却把这个不带用户登录信息的 session ID 保存了下来。</p>
<p><img src="http://lync.in/wp-content/uploads/2011/10/third.png" alt="Third Flash Request" title="Third Flash Request" width="500" height="200" class="aligncenter size-full wp-image-1669" />发现登陆超时后，用户重新登陆，在新的 ID 为 ZZZ 的 session 中留下了有效的登录信息，进入上传页面后，生成了新的拼接 JSESSIONID 的 URL 传递给 Flash 控件，此时进行上传时， Flash 发送的请求既包含了 URL 中的 JSESSIONID，也带了 Cookie 请求头中的 JSESSIONID(图中[1])。按 Servlet 规范，当请求有 Cookie 头中的 JSESSIONID 时，URL 中的就被忽略了，于是服务端判断此请求应该在 YYY 这个 session 中进行处理(图中[2])，于是导致了用户看似已登录，Flash 请求却使用了另一未登录的 session 导致上传失败。</p>
<p>所以，要让 Flash 能够正确使用 URL 中指定的 session，就必须防止 flash cookies 中记录 JSESSIONID 值。如果 Set-cookie 头是 Web 服务器或 Servlet 容器自动加上的，那就需要我们在 Web 应用中将对应的 Cookie 值删除。下面以 Java 代码为例，我们可以通过添加一个名称同样为 JSESSIONID 的立即失效(通过设置 Max-Age=0，参见<a href="http://www.ietf.org/rfc/rfc2109.txt" title="HTTP State Management Mechanism">RFC 2109: HTTP State Management Mechanism</a> 的 4.3.3 节)的 Cookie 来覆盖之前的值：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">Java</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
</pre></td><td class="code"><pre class="java" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">Cookie cookie <span style="color: #CCC;">=</span> <span style="color: #3D9EDD;">new</span> Cookie<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">&quot;JSESSIONID&quot;</span>, <span style="color: #7ACC00;">&quot;&quot;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
cookie.<span style="color: #FFF;">setMaxAge</span><span style="color: #CCC;">&#40;</span><span style="color: #FFCC00;">0</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
response.<span style="color: #FFF;">addCookie</span><span style="color: #CCC;">&#40;</span>cookie<span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></td></tr></table></div></div>

<p>这样在 session 超时时，上传文件失败返回的请求中会带这样的头：</p>
<blockquote><p>
Set-cookie:JSESSIONID=YYY;<br />
Set-cookie:JSESSIONID="";Max-Age=0
</p></blockquote>
<p>于是在 flash cookie 中 YYY 这个 JSESSIONID 刚刚被设置就被清除了，在重新登陆后 Flash 发送的请求就不会带有 Cookie 头，不会覆盖 URL 中设置的值了。</p>
<p>总结一下，虽然这个过程说起来挺复杂，但解决方法还是比较简单明了的：</p>
<ol>
<li>在上传文件的目标 URL 中显式传递 session ID；</li>
<li>在处理上传的应用代码中，当发现无登录信息的 session ID 时，不发送 Set-cookie 头或在应用代码中将其用一个立即失效的同名 cookie 覆盖。</li>
</ol>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/session-trap-on-uploading-files-using-flash-in-firefox/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/session-trap-on-uploading-files-using-flash-in-firefox/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>闲话多提交按钮的HTML表单</title>
		<link>http://lync.in/talking-about-html-forms-with-multiple-submit-buttons/</link>
		<comments>http://lync.in/talking-about-html-forms-with-multiple-submit-buttons/#comments</comments>
		<pubDate>Wed, 05 Oct 2011 12:57:16 +0000</pubDate>
		<dc:creator>Justice</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[submit button]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1625</guid>
		<description><![CDATA[本文作者：Justice在 Web 应用中，最常用的服务器端与客户端的数据交互是通过提交 HTML 表单实现的。以 HTML 4.01 为例，规定当表单提交时，会将 &#60;form&#62; 元素中的 Successful controls 的当前取值提交到服务器。所谓成功控件需要有以下几个条件(但不仅限于此)： 必须有控件名字，即必须包含 name 属性 如果表单中有多个提交按钮，只有被点击的那个按钮可以是成功的 不能是禁用状态，即不含 disabled 属性 不是 Reset button 现在我们考虑一下这样的场景，在某个表单中我们需要用到多个提交按钮(Submit button)，就如同 WordPress 后台写文章那样的表单，我们在编辑完文章内容后，可以选择保存草稿或是直接发布。下面图中所示是一个简化的发布页面，可以填写文章标题、内容之后选某一种提交形式： 对应的 HTML 片段可以是这样： HTML1 2 3 4 5 6 &#60;form action=&#34;http://localhost/blog/new-post&#34; method=&#34;POST&#34;&#62; &#60;input type=&#34;text&#34; name=&#34;title&#34; id=&#34;title&#34; /&#62;&#60;br /&#62; &#60;textarea name=&#34;content&#34; id=&#34;content&#34; cols=&#34;30&#34; rows=&#34;10&#34;&#62;&#60;/textarea&#62;&#60;br /&#62; &#60;input type=&#34;submit&#34; id=&#34;save-post&#34; value=&#34;Save [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/1/" title="Posts by Justice">Justice</a></div><p>在 Web 应用中，最常用的服务器端与客户端的数据交互是通过提交 <abbr title="Hypertext Markup Language">HTML</abbr> 表单实现的。以 HTML 4.01 为例，规定当表单提交时，会将 <code>&lt;form&gt;</code> 元素中的 <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2" title="Successful controls">Successful controls</a> 的当前取值提交到服务器。所谓成功控件需要有以下几个条件(但不仅限于此)：</p>
<ol>
<li>必须有控件名字，即必须包含 name 属性</li>
<li>如果表单中有多个提交按钮，只有被点击的那个按钮可以是成功的</li>
<li>不能是禁用状态，即不含 disabled 属性</li>
<li>不是 Reset button</li>
</ol>
<p>现在我们考虑一下这样的场景，在某个表单中我们需要用到多个提交按钮(Submit button)，就如同 WordPress 后台写文章那样的表单，我们在编辑完文章内容后，可以选择保存草稿或是直接发布。下面图中所示是一个简化的发布页面，可以填写文章标题、内容之后选某一种提交形式：<span id="more-1625"></span><br />
<img src="http://lync.in/wp-content/uploads/2011/10/scenario.png" alt="Scenario" title="Scenario" width="306" height="303" class="aligncenter size-full wp-image-1647" /></p>
<p>对应的 HTML 片段可以是这样：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">form</span> <span style="color: #996699;">action</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;http://localhost/blog/new-post&quot;</span> <span style="color: #996699;">method</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;POST&quot;</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;text&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;title&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;title&quot;</span> <span style="color: #CCC;">/</span>&gt;&lt;<span style="color: #F2B646;">br</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">textarea</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;content&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;content&quot;</span> <span style="color: #996699;">cols</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;30&quot;</span> <span style="color: #996699;">rows</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;10&quot;</span>&gt;&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">textarea</span>&gt;&lt;<span style="color: #F2B646;">br</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;save-post&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;Save Draft&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;publish&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;Publish&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">form</span>&gt;</span></pre></td></tr></table></div></div>

<p>为了在提交时能区分是保存还是发布，需要通过 JavaScript 来为不同的按钮绑定不同的操作：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #999;">//using jQuery</span>
$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'#save-post'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    <span style="color: #999;">//按保存草稿方式提交</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
&nbsp;
$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'#publish'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    <span style="color: #999;">//按发布方式提交</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></td></tr></table></div></div>

<p>那么提交的数据中如何来区分是保存草稿还是发布？通常我们会在 <code>&lt;form&gt;</code> 中添加一个隐藏的控件来保存这个状态，像这样：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #808080;">&lt;!-- value 可以是 publish 或 draft，默认为 publish --&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;hidden&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-status&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-status&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;publish&quot;</span> <span style="color: #CCC;">/</span>&gt;</span></pre></div></div></div>

<p>这样在 JS 中就只需要为按保存方式提交作相应处理：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #999;">//using jQuery</span>
$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'#save-post'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    $<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'#post-status'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">val</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'draft'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></td></tr></table></div></div>

<p>这样如果按 Save Draft，那么 POST 出去的数据就应该是：</p>
<blockquote><p>
title=blah&#038;content=blahblah&#038;post-status=draft
</p></blockquote>
<p>OK，这样的确已经可以正常工作了，但是总觉得让人有些不爽：这么简单的工作为什么还要通过脚本来实现？有没有想过为什么要这样实现呢？事实上，因为在文章开始的地方提到的 HTML 规范中定义了一个表单中有多个提交按钮的情况下，只有一个可以是成功控件从而提交自己的数据值，也就是说，我们给提交按钮加上相同的 name 属性，只有一个按钮会提交相应的数据。那何必还需要隐藏控件？应该只需要这样：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">form</span> <span style="color: #996699;">action</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;http://localhost/blog/post&quot;</span> <span style="color: #996699;">method</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;POST&quot;</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;text&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;title&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;title&quot;</span> <span style="color: #CCC;">/</span>&gt;&lt;<span style="color: #F2B646;">br</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">textarea</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;content&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;content&quot;</span> <span style="color: #996699;">cols</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;30&quot;</span> <span style="color: #996699;">rows</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;10&quot;</span>&gt;&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">textarea</span>&gt;&lt;<span style="color: #F2B646;">br</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-status&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;save-post&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;Save Draft&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">input</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-status&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;publish&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;Publish&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">form</span>&gt;</span></pre></td></tr></table></div></div>

<p>像这样把两个提交按钮的 name 属性都设为 post-status，就可以像服务器发送唯一的 post-status 值了，但有一个问题：post-status 的值只能和按钮上的文字一样了，给 Web 应用的 <acronym title="internationalization">i18n</acronym> 带来了很大的不便。其实 HTML 规范也考虑到了这个问题，这就是为什么我们会有 <code>&lt;button&gt;</code> 元素。HTML 中的按钮共有三种类型：</p>
<ul>
<li>submit buttons</li>
<li>reset buttons</li>
<li>push buttons</li>
</ul>
<p>前两个不用说，第三种按钮没有默认的数据交互行为，需要依赖脚本才能起到作用。一般情况下我们使用的都是 type 属性分别为 submit / reset / button 的 <code>&lt;input&gt;</code> 元素，而 <code>&lt;button&gt;</code> 元素就是用来为这三类 <code>&lt;input&gt;</code> 提供更多渲染可能性的，<code>&lt;button&gt;</code> 中可以插入其他的 HTML 元素，比如可以加入 <code>&lt;img&gt;</code> 来给按钮增加一个图标，所以显然也可以使用任何你想使用的文本作为按钮上显示的文字。这个文字和按钮的取值 value 应当是分离的：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">button</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-type&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;save&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;draft&quot;</span>&gt;</span>Save Draft<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">button</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">button</span> <span style="color: #996699;">type</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;submit&quot;</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;post-type&quot;</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;publish&quot;</span> <span style="color: #996699;">value</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;publish&quot;</span>&gt;</span>Publish<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">button</span>&gt;</span></pre></div></div></div>

<p>看上去很不错，不是么？可是很不幸，我们又遇到麻烦了：在 IE6/7 下，这样的方法完全不能工作。在 IE6 下，用这样的方式按 Save Draft 按钮，POST 出的参数值为：</p>
<blockquote><p>
title=blah&#038;content=blahblah&#038;post-status=Save+Draft&#038;post-status=Publish
</p></blockquote>
<p>在 IE7 下，则是：</p>
<blockquote><p>
title=blah&#038;content=blahblah&#038;post-status=Save+Draft
</p></blockquote>
<p>可以看到，IE6/7 错误地把 <code>&lt;button&gt;</code> 的 innerHTML 当作了 value 发送出去了，而 IE6 甚至把没有点击的按钮也看作成功。WTF！本来很优雅的代码在现实中却是无法完美工作的。有人写了个针对 IE6/7 的 hack 来解决这个问题，即在 <code>&lt;button&gt;</code> 的点击事件中，disable 同一表单内的其他 <code>&lt;button&gt;</code> 并且用其 value 替换 innerHTML，但这样在网速比较慢的情况下(就是大多数情况下)会出现下面这样的画面：<br />
<img src="http://lync.in/wp-content/uploads/2011/10/ie.png" alt="Awkward hack" title="Awkward hack" width="306" height="283" class="aligncenter size-full wp-image-1639" /><br />
这显然也是不能让人接受的。就是没有一个完美的方案，就是这样，所以又回到我们开头的地方了。用隐藏控件来 hold 住提交方式参数，用脚本来给它赋值，又变成了看起来最通用最简单的方案了。</p>
<p>另外有一种观点认为，一个表单就不该有多个提交按钮，提交按钮不该携带任何参数值，完全可以换成单选框、下拉菜单等等等等方式来实现。但实际上多个提交按钮在很多时候可以减少用户的交互操作，并且更为直观，绝对是有其存在价值的。拿 WordPress 的文章发布方式来说，现在就是多提交按钮的：<br />
<img src="http://lync.in/wp-content/uploads/2011/10/original.png" alt="WP Submit" title="WP Submit" width="280" height="215" class="aligncenter size-full wp-image-1642" /><br />
如果改成下面这样，就感觉十分别扭了：<br />
<img src="http://lync.in/wp-content/uploads/2011/10/mod.png" alt="WP Submit Mod" title="WP Submit Mod" width="280" height="205" class="aligncenter size-full wp-image-1645" /></p>
<p>总结一下：如果你可以抛弃 IE6/7，那么恭喜你，用最简单优雅的方式去实现吧！如果不能，那么，还是老老实实地用隐藏控件吧，慢慢等着 IE6/7 入土为安吧。</p>
<p>很久没写东西了，有点虎头蛇尾，其实没多少内容，发发牢骚而已。</p>
<p><ins datetime="2011-10-09T02:22:26+00:00">Update: 欲了解更多关于按钮数据交互行为的浏览器差异可以阅读<a href="http://w3help.org/zh-cn/causes/CM2001">这篇文章</a>。</ins></p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/talking-about-html-forms-with-multiple-submit-buttons/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/talking-about-html-forms-with-multiple-submit-buttons/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>把网站做成App II</title>
		<link>http://lync.in/make-your-site-an-app-ii/</link>
		<comments>http://lync.in/make-your-site-an-app-ii/#comments</comments>
		<pubDate>Sun, 17 Apr 2011 10:15:36 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[IE9]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Site Mode]]></category>
		<category><![CDATA[Thumb Bar]]></category>
		<category><![CDATA[Win7]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1489</guid>
		<description><![CDATA[本文作者：Sinnyn上一篇里面我们介绍了怎么增加任务，这一篇里面将介绍怎么在IE9中增加缩略图控件。 完成之后的效果会是这个样子。 首先要介绍几个API， window.external.msIsSiteMode 判断是否是站点模式 window.external.msSiteModeAddThumbBarButton 加缩略图按钮 window.external.msSiteModeAddButtonStyle 给缩略图按钮增加样式 window.external.msSiteModeShowButtonStyle 显示已定义的缩略图按钮样式 window.external.msSiteModeUpdateThumbBarButton 更新缩略图按钮状态 首先在初始化的时候把缩略图的按钮给加上，代码如下： JavaScriptdocument.addEventListener&#40;'msthumbnailclick', onButtonClicked, false&#41;; //事件响应 &#160; btnPrev = window.external.msSiteModeAddThumbBarButton&#40;path + 'images/prev.ico', 'Previous'&#41;; btnPlay = window.external.msSiteModeAddThumbBarButton&#40;path + 'images/play.ico', 'Play'&#41;; btnNext = window.external.msSiteModeAddThumbBarButton&#40;path + 'images/next.ico', 'Next'&#41;; stylePlay = window.external.msSiteModeAddButtonStyle&#40;btnPlay, path + 'images/play.ico', 'Play'&#41;; stylePause = window.external.msSiteModeAddButtonStyle&#40;btnPlay, path + 'images/pause.ico', 'Pause'&#41;; &#160; window.external.msSiteModeShowThumbBar&#40;&#41;; 这样子的话就能把bar给加到缩略图上去了，在这之后，我们加上几个html5新增的audio的tag，组成一个playlist，那么在这里，我选择的是Kelly Clarkson的Because [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>上一篇里面我们介绍了怎么增加任务，这一篇里面将介绍怎么在IE9中增加缩略图控件。</p>
<p>完成之后的效果会是这个样子。<br />
<img class="alignnone size-full wp-image-1491" title="效果图" src="http://lync.in/wp-content/uploads/2011/04/bar.png" alt="" width="236" height="212" /><br />
<span id="more-1489"></span><br />
首先要介绍几个API，</p>
<ul>
<li><a href="http://msdn.microsoft.com/en-us/library/ff976310(v=vs.85).aspx" target="_blank">window.external.msIsSiteMode</a> 判断是否是站点模式</li>
<li><a href="http://msdn.microsoft.com/en-us/library/ff976313(v=vs.85).aspx" target="_blank">window.external.msSiteModeAddThumbBarButton</a> 加缩略图按钮</li>
<li><a href="http://msdn.microsoft.com/en-us/library/ff976311(v=vs.85).aspx" target="_blank">window.external.msSiteModeAddButtonStyle</a> 给缩略图按钮增加样式</li>
<li><a href="http://msdn.microsoft.com/en-us/library/ff976317(v=vs.85).aspx" target="_blank">window.external.msSiteModeShowButtonStyle</a> 显示已定义的缩略图按钮样式</li>
<li><a href="http://msdn.microsoft.com/en-us/library/ff976320(v=vs.85).aspx" target="_blank">window.external.msSiteModeUpdateThumbBarButton</a> 更新缩略图按钮状态</li>
</ul>
<p>首先在初始化的时候把缩略图的按钮给加上，代码如下：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">document.<span style="color: #FFF;">addEventListener</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'msthumbnailclick'</span><span style="color: #CCC;">,</span> onButtonClicked<span style="color: #CCC;">,</span> <span style="color: #F2B646;">false</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span> <span style="color: #999;">//事件响应</span>
&nbsp;
btnPrev <span style="color: #CCC;">=</span> window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeAddThumbBarButton</span><span style="color: #CCC;">&#40;</span>path <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'images/prev.ico'</span><span style="color: #CCC;">,</span> <span style="color: #7ACC00;">'Previous'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
btnPlay <span style="color: #CCC;">=</span> window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeAddThumbBarButton</span><span style="color: #CCC;">&#40;</span>path <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'images/play.ico'</span><span style="color: #CCC;">,</span> <span style="color: #7ACC00;">'Play'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
btnNext <span style="color: #CCC;">=</span> window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeAddThumbBarButton</span><span style="color: #CCC;">&#40;</span>path <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'images/next.ico'</span><span style="color: #CCC;">,</span> <span style="color: #7ACC00;">'Next'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
stylePlay <span style="color: #CCC;">=</span> window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeAddButtonStyle</span><span style="color: #CCC;">&#40;</span>btnPlay<span style="color: #CCC;">,</span>  path <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'images/play.ico'</span><span style="color: #CCC;">,</span> <span style="color: #7ACC00;">'Play'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
stylePause <span style="color: #CCC;">=</span> window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeAddButtonStyle</span><span style="color: #CCC;">&#40;</span>btnPlay<span style="color: #CCC;">,</span> path <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'images/pause.ico'</span><span style="color: #CCC;">,</span> <span style="color: #7ACC00;">'Pause'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
&nbsp;
window.<span style="color: #FFF;">external</span>.<span style="color: #FFF;">msSiteModeShowThumbBar</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></div></div></div>

<p>这样子的话就能把bar给加到缩略图上去了，在这之后，我们加上几个html5新增的audio的tag，组成一个playlist，那么在这里，我选择的是Kelly Clarkson的Because of you和Beatles的Let it be。</p>
<p>简单的说一下audio这个对象的几个API，</p>
<ul>
<li>canPlayType()  是否能播放该编码格式</li>
<li>play()  播放</li>
<li>pause()  暂停</li>
<li>paused  一个bool值记录表示是否已暂停</li>
<li>currentTime  当前音频已播放的时间</li>
</ul>
<p>所有的控制函数都是加在上文代码中定义的事件响应函数onButtonClicked中的，通过对事件的监听，可以判断是哪个按钮被按下并执行相关的逻辑。</p>
<p>最后播放的效果就会是这样：<br />
<img class="alignnone size-full wp-image-1492" title="播放" src="http://lync.in/wp-content/uploads/2011/04/play.png" alt="" width="234" height="191" /></p>
<p>JavaScript文件的source在<a href="http://lync.in/wp-content/themes/SimpleDark-Lync.in/js/ie9.js">这里</a>，如有需要可以自行查看，另因为这一系列的东西只是IE9特有的，而且是站点模式所特有的，所以在别的浏览器下不会有这样的效果了。</p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/make-your-site-an-app-ii/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/make-your-site-an-app-ii/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>把网站做成App I</title>
		<link>http://lync.in/make-your-site-an-app-i/</link>
		<comments>http://lync.in/make-your-site-an-app-i/#comments</comments>
		<pubDate>Sat, 02 Apr 2011 16:58:04 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[IE9]]></category>
		<category><![CDATA[Jump List]]></category>
		<category><![CDATA[Win7]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1465</guid>
		<description><![CDATA[本文作者：SinnynIE9是个好东西，但更好的一点是Win7和IE9的组合把Web应用app化实现得更彻底了。在接下来的几篇中会简单描述下怎么做这么个事情。 首先我们将在页首的meta里面填加一点东西，比如在Lync.in里面，我们加上这么几行。 HTML&#60;meta name=&#34;msapplication-task&#34; content=&#34;name=About; action-uri=http://lync.in/about/; icon-uri=favicon.ico&#34; /&#62; &#60;meta name=&#34;msapplication-task&#34; content=&#34;name=Projects; action-uri=http://lync.in/projects/; icon-uri=favicon.ico&#34; /&#62; 在这样的一个tag里面一共是有2个参数，其中content的部分可以有4个参数可以配置，并且是用分号来进行分隔。 参数名 描述 name 任务名 action-uri 任务所要触发的绝对或相对地址 icon-uri 任务的图标地址 window-type 任务在何处打开，可选项有tab，self和window。 然后我们把网站拖到任务栏上面。 然后当我们右键打开的时候就能看到我们刚才加的那两行代码的效果了。 Lync.in 是一个多人协作博客，欢迎您 查看原文 以获得更好的阅读体验。]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>IE9是个好东西，但更好的一点是Win7和IE9的组合把Web应用app化实现得更彻底了。在接下来的几篇中会简单描述下怎么做这么个事情。</p>
<p>首先我们将在页首的meta里面填加一点东西，比如在Lync.in里面，我们加上这么几行。</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">meta</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;msapplication-task&quot;</span> <span style="color: #996699;">content</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;name=About; action-uri=http://lync.in/about/; icon-uri=favicon.ico&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">meta</span> <span style="color: #996699;">name</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;msapplication-task&quot;</span> <span style="color: #996699;">content</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;name=Projects; action-uri=http://lync.in/projects/; icon-uri=favicon.ico&quot;</span> <span style="color: #CCC;">/</span>&gt;</span></pre></div></div></div>

<p><span id="more-1465"></span>在这样的一个tag里面一共是有2个参数，其中content的部分可以有4个参数可以配置，并且是用分号来进行分隔。</p>
<table>
<tr>
<th>参数名</th>
<th>描述</th>
</tr>
<tr>
<td>name</td>
<td>任务名</td>
</tr>
<tr>
<td>action-uri</td>
<td>任务所要触发的绝对或相对地址</td>
</tr>
<tr>
<td>icon-uri</td>
<td>任务的图标地址</td>
</tr>
<tr>
<td>window-type</td>
<td>任务在何处打开，可选项有tab，self和window。</td>
</tr>
</table>
<p>然后我们把网站拖到任务栏上面。<br />
<img src="http://lync.in/wp-content/uploads/2011/04/taskbar1.png" alt="" title="拖到任务栏" width="161" height="140" class="aligncenter size-full wp-image-1467" /></p>
<p>然后当我们右键打开的时候就能看到我们刚才加的那两行代码的效果了。<br />
<img src="http://lync.in/wp-content/uploads/2011/04/taskbar2.png" alt="" title="已经添加上的任务" width="237" height="295" class="aligncenter size-full wp-image-1468" /></p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/make-your-site-an-app-i/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/make-your-site-an-app-i/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Comet研究</title>
		<link>http://lync.in/research-on-comet/</link>
		<comments>http://lync.in/research-on-comet/#comments</comments>
		<pubDate>Fri, 10 Sep 2010 14:25:14 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[AJAX polling]]></category>
		<category><![CDATA[Comet]]></category>
		<category><![CDATA[HTTP Streaming]]></category>
		<category><![CDATA[Push Technology]]></category>
		<category><![CDATA[Websocket]]></category>

		<guid isPermaLink="false">http://lync.in/?p=1081</guid>
		<description><![CDATA[本文作者：Sinnyn在Web应用中，客户端的AJAX技术已经非常普遍也非常深入人心了，但与此同时，另一些应用，诸如在线监控，实时数据显示，即时通讯等需要将后台数据变化情况实时显示到前台，这样的由服务器push的行为（也许会让你想到blackberry）则需要另一种方案来解决，也就是本文所要介绍的Comet —— 无需安装插件，保持http长连接的服务器推方案。 以下两点是方案中必须顾及到的。 浏览器通用性，对各种不同实现结构模型的支持。 长连接对于服务器资源的占用，以及服务器的承受能力。 业界对于Comet实现有两种主要的解决方案： 基于AJAX的轮询(long polling)方式 这种方式就是由客户端发出AJAX请求，然后服务端阻塞请求直至有响应或超时。客户端在接收到服务端的指令之后会进行响应并发出新的请求。 从实现层面上来说，当XMLHttpRequest的状态为4也就是load的状态时会进行客户端处理，而Gecko（Firefox）和Webkit（Chrome，Safari）目前支持在readystate为3的时候读取（当然只能读取到所有该请求已返回的串内容，所以需要自行确定指令边界），Trident（IE）目前如果中途去读取会抛出错误，IE8中使用XDomainRequest可以适当解决这个问题（参见Eric Law的COMET Streaming in Internet Explorer）。 目前，开心网采用的是这一种方式。 基于iframe及htmlfile的流(streaming)方式 这种方式是使用了iframe的机制，然后使得这个iframe请求一个特定的URL，并通过对这个页面的加载不断的从服务端抓回数据，这里从服务端抓回的数据大多是对页面当前JavaScript函数的引用和操作。 这个方案的一个明显不足之处是页面会一直显示正在加载，而这在IE上会更明显。Google的天才们想到了用htmlfile的ActiveX控件来解决这个问题的方案，详细描述可以参见Alex Russell的What else is burried down in the depth's of Google's amazing JavaScript? 目前，人人网和GTalk采用的是这种方式。 除了文首所提到的通用性和性能之外，还有几点是需要列入考量范围的。 数据交换的格式。由于数据交换的形式是推送，所以不可避免的会有指令队列的存在，于是数据结构是需要前后台详细约定的，执行指令和数据指令都需要有严格的界定，一般来说，JSON的方案比较普遍。 浏览器本身的连接数限制。HTTP 1.1规范中声明客户端不应该与服务器端建立超过两个的 HTTP 连接，而IE又严格遵守了这一点，所以前台在处理请求的时候需要谨慎控制请求的数量。 其实，Comet技术在AJAX大红大紫的2005年之后的2006年时是业界一个很热的讨论点，目前的这两种方式非常成熟，在dojo，dwr等前端框架中都已经有这样的实现，而Bayeux协议的出现也已经在实质上订下了一种业界的标准。 Comet的框架前端有Pushlet，dwr和dojo等，服务端有Jetty，Meteor，Orbited，Glassfish，Alpha，实现的产品语言也覆盖了Java，C++，Python，Perl，Ruby，Erlang，.Net等。 下一代HTML5中的WebSocket会是Comet的一个新起点，但在那之前，在非插件的web层面应该不会有更进一步的讨论与技术出现。 本文只是对Comet这个技术进行大体的概述，粗陋不明之处难免，在后续的文章中将会对WebSocket进行一定的解释和演示。 参考资料： 这里有一个php的comet的例子How to implement COMET with PHP。 这是developerWorks上对于Comet的介绍。 这是当前Comet的服务器端的一些产品及介绍。 当然，Wikipedia上面对Comet的解释也是非常详尽。 还可以看看AjaxPatterns上面的一些介绍。 最后，CometDaily是个值得去了解最新Comet新闻和知识的地方。 [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>在Web应用中，客户端的AJAX技术已经非常普遍也非常深入人心了，但与此同时，另一些应用，诸如在线监控，实时数据显示，即时通讯等需要将后台数据变化情况实时显示到前台，这样的由服务器push的行为（也许会让你想到blackberry）则需要另一种方案来解决，也就是本文所要介绍的Comet —— 无需安装插件，保持http长连接的服务器推方案。<br />
<span id="more-1081"></span>以下两点是方案中必须顾及到的。</p>
<ol>
<li>浏览器通用性，对各种不同实现结构模型的支持。</li>
<li>长连接对于服务器资源的占用，以及服务器的承受能力。</li>
</ol>
<div id="attachment_1083" class="wp-caption aligncenter" style="width: 316px"><a href="http://lync.in/wp-content/uploads/2010/09/comet.png" class="highslide-image" onclick="return hs.expand(this);"><img class="size-medium wp-image-1083 " title="Comet time line" src="http://lync.in/wp-content/uploads/2010/09/comet-306x450.png" alt="Comet time line" width="306" height="450" /></a><p class="wp-caption-text">Comet的客户端与服务端交互流</p></div>
<p>业界对于Comet实现有两种主要的解决方案：</p>
<ol>
<li>
<h4>基于AJAX的轮询(long polling)方式</h4>
<p>这种方式就是由客户端发出AJAX请求，然后服务端阻塞请求直至有响应或超时。客户端在接收到服务端的指令之后会进行响应并发出新的请求。</p>
<p>从实现层面上来说，当XMLHttpRequest的状态为4也就是load的状态时会进行客户端处理，而Gecko（Firefox）和Webkit（Chrome，Safari）目前支持在readystate为3的时候读取（当然只能读取到所有该请求已返回的串内容，所以需要自行确定指令边界），Trident（IE）目前如果中途去读取会抛出错误，IE8中使用XDomainRequest可以适当解决这个问题（参见Eric Law的<a href="http://blogs.msdn.com/b/ieinternals/archive/2010/04/06/comet-streaming-in-internet-explorer-with-xmlhttprequest-and-xdomainrequest.aspx" target="_blank">COMET Streaming in Internet Explorer</a>）。</p>
<p>目前，开心网采用的是这一种方式。</li>
<li>
<h4>基于iframe及htmlfile的流(streaming)方式</h4>
<p>这种方式是使用了iframe的机制，然后使得这个iframe请求一个特定的URL，并通过对这个页面的加载不断的从服务端抓回数据，这里从服务端抓回的数据大多是对页面当前JavaScript函数的引用和操作。</p>
<p>这个方案的一个明显不足之处是页面会一直显示正在加载，而这在IE上会更明显。Google的天才们想到了用htmlfile的ActiveX控件来解决这个问题的方案，详细描述可以参见Alex Russell的<a href="http://infrequently.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/" target="_blank">What else is burried down in the depth's of Google's amazing JavaScript?</a></p>
<p>目前，人人网和GTalk采用的是这种方式。</li>
</ol>
<p>除了文首所提到的通用性和性能之外，还有几点是需要列入考量范围的。</p>
<ol>
<li>数据交换的格式。由于数据交换的形式是推送，所以不可避免的会有指令队列的存在，于是数据结构是需要前后台详细约定的，执行指令和数据指令都需要有严格的界定，一般来说，JSON的方案比较普遍。</li>
<li>浏览器本身的连接数限制。HTTP 1.1规范中声明客户端不应该与服务器端建立超过两个的 HTTP 连接，而IE又严格遵守了这一点，所以前台在处理请求的时候需要谨慎控制请求的数量。</li>
</ol>
<p>其实，Comet技术在AJAX大红大紫的2005年之后的2006年时是业界一个很热的讨论点，目前的这两种方式非常成熟，在dojo，dwr等前端框架中都已经有这样的实现，而<a href="http://svn.cometd.com/trunk/bayeux/bayeux.html" target="_blank">Bayeux协议</a>的出现也已经在实质上订下了一种业界的标准。</p>
<p>Comet的框架前端有Pushlet，dwr和dojo等，服务端有Jetty，Meteor，Orbited，Glassfish，Alpha，实现的产品语言也覆盖了Java，C++，Python，Perl，Ruby，Erlang，.Net等。</p>
<p>下一代HTML5中的WebSocket会是Comet的一个新起点，但在那之前，在非插件的web层面应该不会有更进一步的讨论与技术出现。</p>
<p>本文只是对Comet这个技术进行大体的概述，粗陋不明之处难免，在后续的文章中将会对WebSocket进行一定的解释和演示。</p>
<p>参考资料：</p>
<ul>
<li>这里有一个php的comet的例子<a href="http://www.zeitoun.net/articles/comet_and_php/start" target="_blank">How to implement COMET with PHP</a>。</li>
<li>这是developerWorks上对于Comet的<a href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/" target="_blank">介绍</a>。</li>
<li>这是当前Comet的服务器端的一些<a href="http://cometdaily.com/maturity.html" target="_blank">产品及介绍</a>。</li>
<li>当然，Wikipedia上面对<a href="http://en.wikipedia.org/wiki/Comet_(programming)" target="_blank">Comet的解释</a>也是非常详尽。</li>
<li>还可以看看AjaxPatterns上面的<a href="http://ajaxpatterns.org/HTTP_Streaming" target="_blank">一些介绍</a>。</li>
<li>最后，<a href="http://cometdaily.com" target="_blank">CometDaily</a>是个值得去了解最新Comet新闻和知识的地方。</li>
</ul>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/research-on-comet/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/research-on-comet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>毁掉你的IE6</title>
		<link>http://lync.in/crash-your-ie6/</link>
		<comments>http://lync.in/crash-your-ie6/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 15:45:40 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[IE6]]></category>
		<category><![CDATA[jQuery crash]]></category>

		<guid isPermaLink="false">http://lync.in/?p=754</guid>
		<description><![CDATA[本文作者：Sinnyn今天下午Justice兴致勃勃的贴出一个jQuery的插件，jQuery Crash。 插件的地址在这里。 其实就代码来说这个脚本就只有一行。 JavaScriptjQuery.crash=function&#40;x&#41;&#123;for&#40;x in document.open&#41;;&#125;; 调用这个函数之后的话，在IE6下你会得到这样一个结果。 进一步的，其实不止document.open，很多函数都会产生类似的结果，比如getAttribute，setAttribute等等。 在调用$.crash()之后，等于是for (undefined in document.open)，有些人说，是因为在document.open这样的一个对象中寻找可迭代的对象时发生了错误所造成的。ECMAScript规范中定义的算法指出for...in是要把对象的每一个可迭代属性依次设进x中，而某一个属性可能就在此时发生了问题。那么这又是为何？有人说可能是在调用内部的[[get]]方法时出现的。 也许只有IE的开发人员才知道这个问题究竟是什么，但无可质疑的是，发现这个JScript bug的人是一个天才。而且他成功的杀掉了IE6。 Lync.in 是一个多人协作博客，欢迎您 查看原文 以获得更好的阅读体验。]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>今天下午Justice兴致勃勃的贴出一个jQuery的插件，jQuery Crash。<br />
插件的地址在<a href="http://plugins.jquery.com/project/crash">这里</a>。<br />
其实就代码来说这个脚本就只有一行。</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">jQuery.<span style="color: #FFF;">crash</span><span style="color: #CCC;">=</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span>x<span style="color: #CCC;">&#41;</span><span style="color: #CCC;">&#123;</span><span style="color: #3D9EDD;">for</span><span style="color: #CCC;">&#40;</span>x <span style="color: #3D9EDD;">in</span> document.<span style="color: #996699;">open</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span><span style="color: #CCC;">&#125;</span><span style="color: #CCC;">;</span></pre></div></div></div>

<p>调用这个函数之后的话，在IE6下你会得到这样一个结果。<br />
<span id="more-754"></span><img class="aligncenter size-full wp-image-755" title="ie-crash" src="http://lync.in/wp-content/uploads/2010/04/ie-crash.png" alt="IE6 Crash" width="363" height="184" /><br />
进一步的，其实不止document.open，很多函数都会产生类似的结果，比如getAttribute，setAttribute等等。<br />
在调用$.crash()之后，等于是for (undefined in document.open)，有些人说，是因为在document.open这样的一个对象中寻找可迭代的对象时发生了错误所造成的。ECMAScript规范中定义的算法指出for...in是要把对象的每一个可迭代属性依次设进x中，而某一个属性可能就在此时发生了问题。那么这又是为何？有人说可能是在调用内部的[[get]]方法时出现的。<br />
也许只有IE的开发人员才知道这个问题究竟是什么，但无可质疑的是，发现这个JScript bug的人是一个天才。而且他成功的杀掉了IE6。<br />
<a href="http://lync.in/wp-content/uploads/2010/04/dead-ie6.jpg" class="highslide-image" onclick="return hs.expand(this);"><img class="aligncenter size-medium wp-image-756" title="Dead IE6" src="http://lync.in/wp-content/uploads/2010/04/dead-ie6-450x299.jpg" alt="Dead IE6" width="450" height="299" /></a></p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/crash-your-ie6/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/crash-your-ie6/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>JavaScript调试技巧一则</title>
		<link>http://lync.in/javascript-debug-tips/</link>
		<comments>http://lync.in/javascript-debug-tips/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 15:55:33 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tricks]]></category>

		<guid isPermaLink="false">http://lync.in/?p=422</guid>
		<description><![CDATA[本文作者：Sinnyn本文所描述的场景并不是常见，如果你的脚本并没有很多层嵌套，如果你的脚本不是以动态载入的形式来执行，那么这个很复杂很纠结很麻烦的事情你应该也不会遇到。 很不幸的，在我的工作中，不但会有一个很深层的递归，会动态的载入JS，而且还有eval这样的global code。哦，对了，还有多frame的操作。 好的，让我们开始这个很棘手的事情。 也许你很经常会看到这样的场景。 是的，这是一个脚本异常，在IE中非常常见的一个脚本异常。那么如果这里的Line是一个9位数呢？比如152345279或者512369027，是不是有点抓狂了呢？ S同学也不是什么超人，做不了这等亿万行代码的工作，入行至今写的代码也不及这个零头。那么为什么会那么多行呢？因为这个已经是内存中的行数了。再之后进去调试，调试器会告诉你，source code is not accessible，的确，这些代码都不是明文写在网页中，并没有document.write()之类或者直接写在&#60;script&#62;中。正如前文所述，这些脚本是用动态加载技术读入的（相关内容可以看这篇博客《动态载入脚本和CSS》），所以其内容是完全载入在内存之中，而在文本的表现中是缺失的。也正是因为如此，其调试才显然相对困难。 当然也有办法。 在调试中，你也许会碰到许许多多层的anonymous function，然后你会对这是哪个函数而迷惑不已。当然，通过local variables，通过去看this的具体内容，你可以大致猜测到具体是哪个函数，但如果用以下这句话，也许会更容易一些。 arguments.callee().toString() 其实这句的目的就是打印出当前调用的函数的内容。当你通过函数的内容来找到对应的代码，事情就容易得多了。在那以后，根据错误消息的提示及对变量的观察，就可以找到问题的根源了。 还有些场合，比如weblogic这样的application server之上，会对脚本文件的长度进行cache，如果你的文件被改动过，那很有可能真正你的浏览器下载的脚本文件并不完全。并极有可能带来一些JS解析执行时的错误。所以，如果碰到错的时候，不妨先看看你到手的JS到底长得啥样。 通过XUL来制作的Firefox在调试的时候，特别是一些比较精确的调试的时候，效果反而不如IE系的几个东西来得舒服。而Opera和Webkit东西在调试的时候，就显得更不方便了。虽然在一般调试的时候，Firebug，DragonFly和Web Inspector依然是非常强大非常好用的工具。 如果有错，还望各位不吝指正。 Lync.in 是一个多人协作博客，欢迎您 查看原文 以获得更好的阅读体验。]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>本文所描述的场景并不是常见，如果你的脚本并没有很多层嵌套，如果你的脚本不是以动态载入的形式来执行，那么这个很复杂很纠结很麻烦的事情你应该也不会遇到。</p>
<p>很不幸的，在我的工作中，不但会有一个很深层的递归，会动态的载入JS，而且还有eval这样的global code。哦，对了，还有多frame的操作。</p>
<p>好的，让我们开始这个很棘手的事情。</p>
<p><span id="more-422"></span>也许你很经常会看到这样的场景。<br />
<img alt="IE Error" src="http://www.west-wind.com/WebLog/images/200801/WindowsLiveWriter/JavaScriptHell_EEE2/ieErrorDialog_thumb.png" title="IE Error" class="aligncenter" width="277" height="210" /></p>
<p>是的，这是一个脚本异常，在IE中非常常见的一个脚本异常。那么如果这里的Line是一个9位数呢？比如152345279或者512369027，是不是有点抓狂了呢？</p>
<p>S同学也不是什么超人，做不了这等亿万行代码的工作，入行至今写的代码也不及这个零头。那么为什么会那么多行呢？因为这个已经是内存中的行数了。再之后进去调试，调试器会告诉你，source code is not accessible，的确，这些代码都不是明文写在网页中，并没有document.write()之类或者直接写在&lt;script&gt;中。正如前文所述，这些脚本是用动态加载技术读入的（相关内容可以看这篇博客《<a href="http://lync.in/dynamic-script-and-css-loading/" target="_blank">动态载入脚本和CSS</a>》），所以其内容是完全载入在内存之中，而在文本的表现中是缺失的。也正是因为如此，其调试才显然相对困难。</p>
<p>当然也有办法。</p>
<p>在调试中，你也许会碰到许许多多层的anonymous function，然后你会对这是哪个函数而迷惑不已。当然，通过local variables，通过去看this的具体内容，你可以大致猜测到具体是哪个函数，但如果用以下这句话，也许会更容易一些。<br />
<code>arguments.callee().toString()</code></p>
<p>其实这句的目的就是打印出当前调用的函数的内容。当你通过函数的内容来找到对应的代码，事情就容易得多了。在那以后，根据错误消息的提示及对变量的观察，就可以找到问题的根源了。</p>
<p>还有些场合，比如weblogic这样的application server之上，会对脚本文件的长度进行cache，如果你的文件被改动过，那很有可能真正你的浏览器下载的脚本文件并不完全。并极有可能带来一些JS解析执行时的错误。所以，如果碰到错的时候，不妨先看看你到手的JS到底长得啥样。</p>
<p>通过XUL来制作的Firefox在调试的时候，特别是一些比较精确的调试的时候，效果反而不如IE系的几个东西来得舒服。而Opera和Webkit东西在调试的时候，就显得更不方便了。虽然在一般调试的时候，Firebug，DragonFly和Web Inspector依然是非常强大非常好用的工具。</p>
<p>如果有错，还望各位不吝指正。</p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/javascript-debug-tips/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/javascript-debug-tips/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>实现跨页音乐播放</title>
		<link>http://lync.in/how-to-play-music-across-pages/</link>
		<comments>http://lync.in/how-to-play-music-across-pages/#comments</comments>
		<pubDate>Wed, 16 Sep 2009 17:48:27 +0000</pubDate>
		<dc:creator>Justice</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[cross-page]]></category>
		<category><![CDATA[frameset]]></category>
		<category><![CDATA[music]]></category>

		<guid isPermaLink="false">http://lync.in/?p=246</guid>
		<description><![CDATA[本文作者：Justice注：其实媒体文件的播放都可以采用本文的方法，这里仅以音乐为例。 很多喜欢音乐的朋友都喜欢在自己的站点中分享自己喜欢的音乐。通常除了直接给出音乐文件下载地址，还可以在文章内容中嵌入播放器，使读者可以在阅读内容的时候很方便地播放。可以使用Flash或者JavaScript的播放器。Yahoo! Media Player 和 JW FLV Media Player 都是不错的选择。但是在播放一首曲目的时候，如果用户想切换到别的页面浏览别的内容，播放就会终止。那如何做到在用户切换页面的时候，使音乐继续播放呢？ 其实只要遵循一个原则就可以做到——播放器所在的页面不进行跳转。也就是说，要么将其他内容与播放器分离，要么整个站点的内容都在一个页面内，采用动态加载。 播放器与内容分离 有两种方法：弹出新窗口进行播放和使用框架。 弹出新窗口 这个很容易理解，谷歌音乐就是采取的这个方式。这个方式使得播放器完全分离在另一个窗口，感觉上和使用本地播放器进行播放效果类似，比较之下其优势在于可以在播放窗口安排更多的个性化功能。但是这个方法要多开一个浏览器窗口，总让人感觉不那么自然。 使用框架 这个方法和上一个其实没有本质的区别，最大的不同就是将独立的窗口放在一个frame中，这样就可以在同一个视图中进行播放器的控制和站点其他内容的浏览了。上一次的测试文章就是使用的这个方法。 稍微介绍一下我使用的这个方法。将frameset分为上下两个frame，上面的主窗口就放站点原来的页面，在下面的frame中嵌入包含JW Player的player.html。包含frameset的网页代码大致如下： HTML1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 &#60;html&#62; &#60;head&#62; &#60;title&#62;My Website&#60;/title&#62; &#60;/head&#62; &#60;!-- 下面rows=&#34;*, 20px&#34;表示，页面上部自适应高度，下部固定20px高，可自己调整 --&#62; &#60;frameset id=&#34;f&#34; rows=&#34;*, 20px&#34; border=&#34;0&#34;&#62; &#60;!-- 下面这个frame指向你的网站路径 --&#62; &#60;frame [...]]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/1/" title="Posts by Justice">Justice</a></div><p>注：其实媒体文件的播放都可以采用本文的方法，这里仅以音乐为例。</p>
<p>很多喜欢音乐的朋友都喜欢在自己的站点中分享自己喜欢的音乐。通常除了直接给出音乐文件下载地址，还可以在文章内容中嵌入播放器，使读者可以在阅读内容的时候很方便地播放。可以使用Flash或者JavaScript的播放器。<a href="http://developer.yahoo.com/mediaplayer/">Yahoo! Media Player</a> 和 <a href="http://www.longtailvideo.com/players/jw-flv-player/">JW FLV Media Player</a> 都是不错的选择。但是在播放一首曲目的时候，如果用户想切换到别的页面浏览别的内容，播放就会终止。那如何做到在用户切换页面的时候，使音乐继续播放呢？</p>
<p><span id="more-246"></span>其实只要遵循一个原则就可以做到——播放器所在的页面不进行跳转。也就是说，要么将其他内容与播放器分离，要么整个站点的内容都在一个页面内，采用动态加载。</p>
<h4>播放器与内容分离</h4>
<p>有两种方法：弹出新窗口进行播放和使用框架。</p>
<h5>弹出新窗口</h5>
<p>这个很容易理解，<a href="http://www.google.cn/music/homepage">谷歌音乐</a>就是采取的这个方式。这个方式使得播放器完全分离在另一个窗口，感觉上和使用本地播放器进行播放效果类似，比较之下其优势在于可以在播放窗口安排更多的个性化功能。但是这个方法要多开一个浏览器窗口，总让人感觉不那么自然。</p>
<h5>使用框架</h5>
<p>这个方法和上一个其实没有本质的区别，最大的不同就是将独立的窗口放在一个frame中，这样就可以在同一个视图中进行播放器的控制和站点其他内容的浏览了。上一次的<a href="http://lync.in/test-playing-music-across-pages/">测试文章</a>就是使用的这个方法。</p>
<p>稍微介绍一下我使用的这个方法。将frameset分为上下两个frame，上面的主窗口就放站点原来的页面，在下面的frame中嵌入包含JW Player的<code>player.html</code>。包含frameset的网页代码大致如下：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">HTML</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="html4strict" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">html</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">head</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">title</span>&gt;</span>My Website<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">title</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">head</span>&gt;</span>
<span style="color: #808080;">&lt;!-- 下面rows=&quot;*, 20px&quot;表示，页面上部自适应高度，下部固定20px高，可自己调整 --&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">frameset</span> <span style="color: #996699;">id</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;f&quot;</span> <span style="color: #996699;">rows</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;*, 20px&quot;</span> <span style="color: #996699;">border</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;0&quot;</span>&gt;</span>
    <span style="color: #808080;">&lt;!-- 下面这个frame指向你的网站路径 --&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">frame</span> <span style="color: #996699;">src</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;http://www.my-website.com&quot;</span> <span style="color: #996699;">frameborder</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;0&quot;</span> <span style="color: #996699;">noresize</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;true&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
    <span style="color: #808080;">&lt;!-- 下面这个frame指向播放器路径 --&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">frame</span> <span style="color: #996699;">src</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;player.html&quot;</span> <span style="color: #996699;">frameborder</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;0&quot;</span> <span style="color: #996699;">scrolling</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;no&quot;</span> <span style="color: #996699;">noresize</span><span style="color: #CCC;">=</span><span style="color: #7ACC00;">&quot;true&quot;</span> <span style="color: #CCC;">/</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">frameset</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">noframes</span>&gt;</span>
    <span style="color: #CCFF33;">&lt;<span style="color: #F2B646;">body</span>&gt;</span>
        <span style="color: #808080;">&lt;!-- 如果浏览器不支持框架，显示如下内容 --&gt;</span>
        Sorry, your browser does not support frameset.
    <span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">body</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">noframes</span>&gt;</span>
<span style="color: #CCFF33;">&lt;<span style="color: #CCC;">/</span><span style="color: #F2B646;">html</span>&gt;</span></pre></td></tr></table></div></div>

<p>下载JW Player后将其包含的播放器Flash文件及<code>swfobject.js</code>均解压到站点相应目录。可以去JW Player的官网使用其设置向导进行代码生成，直接copy到<code>player.html</code>中。生成的代码包含这样一句：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #F2B646;">var</span> so <span style="color: #CCC;">=</span> <span style="color: #F2B646;">new</span> SWFObject<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'player-viral.swf'</span><span style="color: #CCC;">,</span><span style="color: #7ACC00;">'mpl'</span><span style="color: #CCC;">,</span><span style="color: #7ACC00;">'100%'</span><span style="color: #CCC;">,</span><span style="color: #7ACC00;">'19'</span><span style="color: #CCC;">,</span><span style="color: #7ACC00;">'9'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></div></div></div>

<p>其中的<code>'mpl'</code>是生成的播放器对象的id和name，之后还会用上。当然也可以自己起别的名字。</p>
<p>现在播放器只能播放初始化时预设的那个曲目，已经可以实现跨页播放，不过还需要进一步的改进。我们可能在站点内多处提供了音乐资源，希望用户可以根据喜好选择播放器内播放的曲目。接下来可以使用JS来控制播放器播放的曲目。由于这些功能在不使用frameset时不需要，我们可以在页面初始化时，通过检查是否存在frameset来判断是否需要动态加载实现这些功能的JS代码。我使用的是jQuery的动态加载方法，如果顶层窗口内存在2个frame，就进行加载：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #3D9EDD;">if</span><span style="color: #CCC;">&#40;</span>top.<span style="color: #FFF;">frames</span><span style="color: #CCC;">&#91;</span><span style="color: #FFCC00;">1</span><span style="color: #CCC;">&#93;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    $.<span style="color: #FFF;">getScript</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'http://lync.in/frame.js'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span></pre></div></div></div>

<p>首先，我们希望在音乐文件的链接后给出一个播放按钮。在发布需要支持跨页播放的音乐链接时，我们可以给相应的<code>&lt;a&gt;</code>标签添加class="play"，然后使用jQuery来完成按钮的添加：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'a.play[href]'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">each</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span> <span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    $<span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">this</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">after</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'&lt;span&gt;[&lt;a class=&quot;play_button&quot; href=&quot;javascript:playAudio(<span style="color: #99FF00;">\'</span>'</span> <span style="color: #CCC;">+</span> $<span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">this</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">attr</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'href'</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">+</span> <span style="color: #7ACC00;">'<span style="color: #99FF00;">\'</span>);&quot;&gt;Play&lt;/a&gt;]&lt;/span&gt;'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></div></div></div>

<p>接下来就是完成<code>playAudio</code>这个函数的功能。首先，在<code>player.html</code>的JS代码中添加：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #F2B646;">function</span> thePlayer<span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    <span style="color: #3D9EDD;">if</span><span style="color: #CCC;">&#40;</span>navigator.<span style="color: #FFF;">appName</span>.<span style="color: #FFF;">indexOf</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">&quot;Microsoft&quot;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">!=</span> <span style="color: #CCC;">-</span><span style="color: #FFCC00;">1</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
        <span style="color: #3D9EDD;">return</span> window<span style="color: #CCC;">&#91;</span><span style="color: #7ACC00;">'mpl'</span><span style="color: #CCC;">&#93;</span><span style="color: #CCC;">;</span>
    <span style="color: #CCC;">&#125;</span> <span style="color: #3D9EDD;">else</span> <span style="color: #CCC;">&#123;</span>
        <span style="color: #3D9EDD;">return</span> document<span style="color: #CCC;">&#91;</span><span style="color: #7ACC00;">'mpl'</span><span style="color: #CCC;">&#93;</span><span style="color: #CCC;">;</span>
    <span style="color: #CCC;">&#125;</span>
<span style="color: #CCC;">&#125;</span>
<span style="color: #F2B646;">var</span> player <span style="color: #CCC;">=</span> thePlayer<span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></td></tr></table></div></div>

<p>这就取得了播放器的JS对象，在主页面中可以使用<code>top.frames[1].player</code>对其进行引用。注意上面<code>'mpl'</code>需要和在SWFObject对象初始化时设定的id相同。然后只要在点击Play按钮时给播放器发送相应事件就可以更新其播放的内容：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;"><span style="color: #F2B646;">function</span> playAudio<span style="color: #CCC;">&#40;</span>src<span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    player.<span style="color: #FFF;">sendEvent</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'STOP'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    player.<span style="color: #FFF;">sendEvent</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'LOAD'</span><span style="color: #CCC;">,</span> src<span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    player.<span style="color: #FFF;">sendEvent</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'PLAY'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span></pre></td></tr></table></div></div>

<p>这样，整个站点内<code>class="play"</code>的音乐链接都会动态加上Play按钮，并可以在站内实现跨页面播放了。</p>
<p>还有几个小细节需要完善。在带框架的页面内再点击导航向框架页面会导致框架嵌套，可以使用JS处理页面内所有链接，在遇到导航向框架页的链接时，在顶层窗口进行跳转。在这里我带框架的页面地址为<code>http://lync.in/go.php</code>：</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><div class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'a[href^=&quot;http://lync.in/go.php&quot;]'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    top.<span style="color: #FFF;">window</span>.<span style="color: #FFF;">location</span>.<span style="color: #FFF;">href</span> <span style="color: #CCC;">=</span> $<span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">this</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">attr</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'href'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span></pre></div></div></div>

<p>除此之外，当点击站外链接时，也应该在顶层窗口进行跳转。在使用框架时，点击某个frame中的链接并不会改变顶层窗口的title和地址栏链接。</p>

<div class="wp_syntax_wrapper"><span class="wp_syntax_lang">JavaScript</span><div class="wp_syntax" style="background:#2c2c2c; overflow:auto"><table><tr><td class="line_numbers" style="color:#eee; background:#3c3c3c"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="code"><pre class="javascript" style="color: #FFF; font-family:&quot;Consolas&quot;,monospace,&quot;Courier New&quot;">$<span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'a'</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    top.<span style="color: #FFF;">document</span>.<span style="color: #FFF;">title</span> <span style="color: #CCC;">=</span> <span style="color: #7ACC00;">'Loading...'</span><span style="color: #CCC;">;</span> <span style="color: #999;">//点击链接时先将title设为&quot;loading...&quot;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">filter</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    <span style="color: #F2B646;">var</span> href <span style="color: #CCC;">=</span> $<span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">this</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">attr</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'href'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    <span style="color: #3D9EDD;">if</span><span style="color: #CCC;">&#40;</span>href<span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
        <span style="color: #999;">//经过滤选出站外链接</span>
        <span style="color: #3D9EDD;">return</span> <span style="color: #CCC;">!</span><span style="color: #CCC;">&#40;</span>href.<span style="color: #FFF;">indexOf</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'http://'</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">==</span> <span style="color: #CCC;">-</span><span style="color: #FFCC00;">1</span> <span style="color: #CCC;">||</span> href.<span style="color: #FFF;">indexOf</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'http://lync.in/'</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">==</span> <span style="color: #FFCC00;">0</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    <span style="color: #CCC;">&#125;</span>
    <span style="color: #3D9EDD;">return</span> <span style="color: #F2B646;">true</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">click</span><span style="color: #CCC;">&#40;</span><span style="color: #F2B646;">function</span><span style="color: #CCC;">&#40;</span><span style="color: #CCC;">&#41;</span> <span style="color: #CCC;">&#123;</span>
    top.<span style="color: #FFF;">window</span>.<span style="color: #FFF;">location</span>.<span style="color: #FFF;">href</span> <span style="color: #CCC;">=</span> $<span style="color: #CCC;">&#40;</span><span style="color: #3D9EDD;">this</span><span style="color: #CCC;">&#41;</span>.<span style="color: #FFF;">attr</span><span style="color: #CCC;">&#40;</span><span style="color: #7ACC00;">'href'</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
    <span style="color: #3D9EDD;">return</span> <span style="color: #F2B646;">false</span><span style="color: #CCC;">;</span>
<span style="color: #CCC;">&#125;</span><span style="color: #CCC;">&#41;</span><span style="color: #CCC;">;</span>
top.<span style="color: #FFF;">document</span>.<span style="color: #FFF;">title</span> <span style="color: #CCC;">=</span> document.<span style="color: #FFF;">title</span><span style="color: #CCC;">;</span> <span style="color: #999;">//让顶层窗口的title和主窗口title相同</span></pre></td></tr></table></div></div>

<p>用上面的方法，可在新页面加载的时候用JS将title更新。而对地址栏的链接就没有什么完美的方法了，可以采取<a href="http://www.billboard.com/">Billboard</a>的解决方案，后面会说。</p>
<h4>全站动态加载</h4>
<p>整个站点都不刷页，点击链接都以AJAX的方式进行加载，或者直接全站Flash/Flex。</p>
<p>这个方法有一个很好的例子是<a href="http://www.billboard.com/">Billboard</a>。它所有的音乐都使用页面左侧的JS播放器进行播放，并有调整播放列表等功能，而页面的跳转全部都使用JS来处理。而地址栏URL它采用了页内链接的方式，点击后不刷页，但是可以更新地址栏URL。这样，用JS将普通的链接在点击时转换为页内链接，就可以不刷新页面而且更新地址栏了。如果我们应用到框架方法中，那就可以在点击站内链接时，先将顶层窗口定向到相应页内链接，然后<code>return true</code>就行了。同时，如果用户使用带有'#'的链接进行直接访问，也应该在服务器端做相应处理，给出相应的frame源地址。但Wordpress站点一般都含有带页内锚点的链接，比如<code>http://lync.in/how-to-play-music-across-pages/#comments</code>，这样处理起来就比较麻烦了。</p>
<p>个人不太喜欢全站Flash/Flex的站点，虽然效果够炫，但是这样屏蔽了浏览器的不少功能，可能会与用户长期养成的使用习惯发生冲突。比如在访问Flash站点时，就无法使用浏览器的返回按钮进行回退了，更别说鼠标手势等等功能了。</p>
<p>就这点体会了，如果大家有更好的方法来实现这个效果，希望不吝赐教。</p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/how-to-play-music-across-pages/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/how-to-play-music-across-pages/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>JavaScript调试工具推荐</title>
		<link>http://lync.in/javascript-dev-tools/</link>
		<comments>http://lync.in/javascript-dev-tools/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 01:26:10 +0000</pubDate>
		<dc:creator>Sinnyn</dc:creator>
				<category><![CDATA[Web Development]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://lync.in/?p=220</guid>
		<description><![CDATA[本文作者：Sinnyn好的工具能帮助你事半功倍，至少你能很快的解决问题。或许你对于Visual Studio和Eclipse的调试器印象深刻，而对于JavaScript这样完全基于浏览器的调试无所适从（其实JavaScript的应用场景远远不止于浏览器），那么这篇简介或许能帮到你。 Internet Explorer Microsoft Script Editor 这是Microsoft自己的一个调试器，要使用它以前确保你有Office。安装方法很简单，Word或别的Office组件中，工具-&#62;宏-&#62;Microsoft脚本编辑器，安装完以后记得安装web调试。然后在IE的高级选项中记得清除“禁用Internet Explorer调试”前的勾。 Internet Explorer Developer Toolbar 对于IE的样式而言这个实在是太关键的工具了。[下载地址] 另外要注意的是，IE8里面内置了这一款工具，而且也提供了一个非常好的调试环境，所以你完全可以信赖。 IETester 每一个Web Designer都非常痛恨IE6，与此同时，IE7与IE8之间也有着一些细小的区别。在当前IE6任然占据相当市场份额的现状之下，调试多个IE版本任然是需要的。曾经用过MultipleIE，但发现这款软件的稳定性不佳，直到后来找到这款软件。[下载地址] Firefox Firebug 不解释，在Firefox下这个便是王道，唯一可能比较差的就是在面对相当复杂的脚本操作的时候可能在调试脚本中会碰到一些困难。 YSlow和Page Speed 互联网大亨Yahoo!和Google的开发人员他们对于Web的经验在这两个小插件中绝对的体现，如果你想提升你的网站的性能（不是UI），那么，你最好听取他们的建议。 Safari 用Safari自己的吧，也没什么别的选择。 Chrome 同Safari，现在Chrome的插件机制并不成熟，而且，请相信Google工程师的技术能力。 Opera Opera的DragonFly调试器也是很强大的，只是国内的O粉不多。 HTTP工具 Fiddler Fiddler是一款Proxy，不是用来给你翻墙的，只是为了监控你的web行为，它可以看你的web请求，仿造request和response，看网页加载过程中的timeline等等。[下载地址] 注：Fiddler需要.NET Framework 2.0支持。 Lync.in 是一个多人协作博客，欢迎您 查看原文 以获得更好的阅读体验。]]></description>
			<content:encoded><![CDATA[<div class="feed-before" style="margin:15px 0; clear:both;">本文作者：<a href="http://lync.in/author/3/" title="Posts by Sinnyn">Sinnyn</a></div><p>好的工具能帮助你事半功倍，至少你能很快的解决问题。或许你对于Visual Studio和Eclipse的调试器印象深刻，而对于JavaScript这样完全基于浏览器的调试无所适从（其实JavaScript的应用场景远远不止于浏览器），那么这篇简介或许能帮到你。</p>
<h3>Internet Explorer</h3>
<h4>Microsoft Script Editor</h4>
<p>这是Microsoft自己的一个调试器，要使用它以前确保你有Office。安装方法很简单，Word或别的Office组件中，工具-&gt;宏-&gt;Microsoft脚本编辑器，安装完以后记得安装web调试。然后在IE的高级选项中记得清除“禁用Internet Explorer调试”前的勾。<span id="more-220"></span></p>
<h4>Internet Explorer Developer Toolbar</h4>
<p>对于IE的样式而言这个实在是太关键的工具了。[<a href="http://www.microsoft.com/downloadS/details.aspx?familyid=E59C3964-672D-4511-BB3E-2D5E1DB91038&#038;displaylang=en">下载地址</a>]<br />
另外要注意的是，IE8里面内置了这一款工具，而且也提供了一个非常好的调试环境，所以你完全可以信赖。</p>
<h4>IETester</h4>
<p>每一个Web Designer都非常痛恨IE6，与此同时，IE7与IE8之间也有着一些细小的区别。在当前IE6任然占据相当市场份额的现状之下，调试多个IE版本任然是需要的。曾经用过MultipleIE，但发现这款软件的稳定性不佳，直到后来找到这款软件。[<a href="http://www.my-debugbar.com/ietester/install-ietester-v0.3.5.exe">下载地址</a>]</p>
<h3>Firefox</h3>
<h4>Firebug</h4>
<p>不解释，在Firefox下这个便是王道，唯一可能比较差的就是在面对相当复杂的脚本操作的时候可能在调试脚本中会碰到一些困难。</p>
<h4>YSlow和Page Speed</h4>
<p>互联网大亨Yahoo!和Google的开发人员他们对于Web的经验在这两个小插件中绝对的体现，如果你想提升你的网站的性能（不是UI），那么，你最好听取他们的建议。</p>
<h3>Safari</h3>
<p>用Safari自己的吧，也没什么别的选择。</p>
<h3>Chrome</h3>
<p>同Safari，现在Chrome的插件机制并不成熟，而且，请相信Google工程师的技术能力。</p>
<h3>Opera</h3>
<p>Opera的DragonFly调试器也是很强大的，只是国内的O粉不多。</p>
<h3>HTTP工具</h3>
<h4>Fiddler</h4>
<p>Fiddler是一款Proxy，不是用来给你翻墙的，只是为了监控你的web行为，它可以看你的web请求，仿造request和response，看网页加载过程中的timeline等等。[<a href="http://www.fiddler2.com/fiddler2/">下载地址</a>]<br />
注：Fiddler需要.NET Framework 2.0支持。</p>
<div class="feed-after" style="margin:15px 0; clear:both;"><a href="http://lync.in">Lync.in</a> 是一个多人协作博客，欢迎您 <a href="http://lync.in/javascript-dev-tools/">查看原文</a> 以获得更好的阅读体验。</div>]]></content:encoded>
			<wfw:commentRss>http://lync.in/javascript-dev-tools/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

