<?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>Oceanic / 人生海海 &#187; Web</title>
	<atom:link href="http://tzangms.com/category/web/feed" rel="self" type="application/rss+xml" />
	<link>http://tzangms.com</link>
	<description></description>
	<lastBuildDate>Thu, 02 Sep 2010 01:31:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Facebook 接下來的動作</title>
		<link>http://tzangms.com/programming/2702</link>
		<comments>http://tzangms.com/programming/2702#comments</comments>
		<pubDate>Sat, 21 Aug 2010 14:02:26 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Facebook]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[facebook]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2702</guid>
		<description><![CDATA[其實最近下班時間都在忙著寫 Facebook 的東西, 所以不得不不關注一下 Facebook 的東西。 自從 Facebook 推出 Graph API 之後, 就開始把目標往 Facebook 之外的網站拓展, 透過 OAuth 2.0、Graph API 跟 Javascript SDK 就可以很容易自己的網站上整合 Facebook 的功能進來。 而 Facebook 上的 Application 也開始建議使用 iframe 取代 FBML, 因為透過新的 SDK 便可以達到原本 FBML 才能達到的功能。 而接下來 Facebook 打算把 App 的開發更 simplify, 他們把 Facebook 站內的開發跟站外的開發變成是同一件事! 因為除了 canvas 要改用 OAuth 2.0 之外, profile tab [...]]]></description>
			<content:encoded><![CDATA[<p>其實最近下班時間都在忙著寫 Facebook 的東西, 所以不得不不關注一下 Facebook 的東西。</p>
<p>自從 Facebook 推出 <a href="http://developers.facebook.com/docs/api">Graph API</a> 之後, 就開始把目標往 Facebook 之外的網站拓展, 透過 <a href="http://developers.facebook.com/docs/authentication/">OAuth 2.0</a>、<a href="http://developers.facebook.com/docs/api">Graph API</a> 跟 <a href="http://developers.facebook.com/docs/reference/javascript/">Javascript SDK</a> 就可以很容易自己的網站上整合 Facebook 的功能進來。 而 Facebook 上的 Application 也開始建議使用 iframe 取代 FBML, 因為透過新的 SDK 便可以達到原本 FBML 才能達到的功能。</p>
<p>而接下來 Facebook 打算把 App 的開發更 simplify, 他們把 Facebook 站內的開發跟站外的開發變成是同一件事! 因為除了 canvas 要改用 OAuth 2.0 之外, profile tab 也要改用 iframe 了!!!</p>
<p>我想都改用 iframe 之後, Facebook 的 server 也會輕鬆很多吧? 原本的 FBML 的作法會一直 fetch html 回來 parse, 以後似乎只剩下 &lt;fb:serverFbml&gt; 這件事了。</p>
<p>在 <a href="http://developers.facebook.com/blog/post/402">Facebook Platform Roadmap Update</a> 這篇文章中提到以下幾點:</p>
<p>1. canvas 也將採用 OAuth 2.0 的新方式<br />
2. profile tab 也將從 FBML 改用 iframe<br />
3. 移除 user page 的 profile tab ( 粉絲頁當然還是保留 )<br />
4. 拿掉 REST API, Data Store API 還有一些 social plugin 可以取代的 FBML tag</p>
<p>其實現在去看 <a href="http://www.facebook.com/developers/apps.php">application settings</a> 就可以看到介面也整個簡化了, 左邊的 tabs 縮減成了 5 個, 也已經出現了 OAuth 2.0 for Canvas (beta) 這個選項。 </p>
<p>我想今年年底一定又有一堆 Facebook 相關的開發者要哀號了, 沒事還是多看看 <a href="http://developers.facebook.com/roadmap">Developer Roadmap</a> 先做好心理準備吧 XD 不過最快的是下禮拜的 profile tab 要變成 520px 的寬度了阿 &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2702/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stashboard</title>
		<link>http://tzangms.com/programming/2690</link>
		<comments>http://tzangms.com/programming/2690#comments</comments>
		<pubDate>Sat, 24 Jul 2010 03:23:32 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[status]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2690</guid>
		<description><![CDATA[Stashboard, 類似 Google 的 Apps Status Dashboard 及 Amazon 的 AWS Service Health Dashboard 的 Status page。 UI 看起來很不賴, 用 Python 在 Google App Engine 上面跑。 所以只需要下載 source code 回來改一下 app-id 就可以 deploy 上 GAE, 只需要不到一分鐘就可以架起來了。 而且有 REST API 喔! 不過我本來以為有自動監測這種功能說 XD]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.stashboard.org/"><img src="http://tzangms.com/wp-content/uploads/2010/07/螢幕快照-2010-07-24-上午11.19.57-500x138.png" alt="" title="螢幕快照 2010-07-24 上午11.19.57" width="500" height="138" class="aligncenter size-large wp-image-2691" /></a></p>
<p><a href="http://www.stashboard.org/">Stashboard</a>, 類似 Google 的 <a href="http://www.google.com/appsstatus">Apps Status Dashboard</a> 及 Amazon 的 <a href="http://status.aws.amazon.com/">AWS Service Health Dashboard</a> 的 Status page。</p>
<p>UI 看起來很不賴, 用 Python 在 Google App Engine 上面跑。 所以只需要下載 source code 回來改一下 app-id 就可以 deploy 上 GAE, 只需要不到一分鐘就可以架起來了。 而且有 REST API 喔! </p>
<p>不過我本來以為有自動監測這種功能說 XD</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2690/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linode 7 歲, 記憶體大放送!</title>
		<link>http://tzangms.com/linux/2676</link>
		<comments>http://tzangms.com/linux/2676#comments</comments>
		<pubDate>Wed, 16 Jun 2010 16:48:51 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[linode]]></category>
		<category><![CDATA[vps]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2676</guid>
		<description><![CDATA[原本 360MB 加到 512MB, 而 512MB 加到了 768 了, 超 high XD 有用 linode 的人記得連上去 reboot 一下, reboot 之後就生效了! 詳情請看 Linode Turns 7, BIG RAM Increase]]></description>
			<content:encoded><![CDATA[<p>原本 360MB 加到 512MB,  而 512MB 加到了 768 了, 超 high XD 有用 linode 的人記得連上去 reboot 一下, reboot 之後就生效了! 詳情請看<br />
<a href="http://blog.linode.com/2010/06/16/linode-turns-7-big-ram-increase/">Linode Turns 7, BIG RAM Increase</a> </p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/linux/2676/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Amazon S3 Console 出現了!</title>
		<link>http://tzangms.com/programming/2674</link>
		<comments>http://tzangms.com/programming/2674#comments</comments>
		<pubDate>Thu, 10 Jun 2010 10:34:31 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[amazon]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2674</guid>
		<description><![CDATA[剛針灸回來就收到 amazon 的信, 好 high 阿 XD 介面使用起來還滿流暢的, 有在用 S3 的人趕快去看看吧!]]></description>
			<content:encoded><![CDATA[<p><a href="http://tzangms.com/wp-content/uploads/2010/06/螢幕快照-2010-06-10-下午6.29.33.png"><img src="http://tzangms.com/wp-content/uploads/2010/06/螢幕快照-2010-06-10-下午6.29.33-500x294.png" alt="" title="螢幕快照 2010-06-10 下午6.29.33" width="500" height="294" class="aligncenter size-large wp-image-2673" /></a><br />
剛針灸回來就收到 amazon 的信, 好 high 阿 XD 介面使用起來還滿流暢的, 有在用 S3 的人趕快去看看吧!</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2674/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 app engine 使用 django</title>
		<link>http://tzangms.com/programming/2672</link>
		<comments>http://tzangms.com/programming/2672#comments</comments>
		<pubDate>Thu, 10 Jun 2010 04:02:23 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[django]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2672</guid>
		<description><![CDATA[因為平常就是寫 django, 然後又對 app engine webapp 的 request handler get/post 分離有點感冒, 不過我想這是習慣問題吧, 所以後來都把 webapp 寫的東西都換成 django。 以前有看過一些文章說是把 django zip 起來, 然後用 zipimport 來跑 django, 不過其實除非你要用的是 django trunk, 否則 app engine 其實本身就內建了 0.96, 1.0 跟 1.1, 當然這邊指的是雲的那一端, 本地端還是得裝上要使用的 django 版本, 不過不用把 django 放進你的 app engine project 就是了。 像是下面這段, 即使你使用的是 webapp, 你仍然可以透過下面這段 code, 寫在 request handler 的最前方, [...]]]></description>
			<content:encoded><![CDATA[<p>因為平常就是寫 <a href="http://www.djangoproject.com/">django</a>, 然後又對 <a href="http://code.google.com/intl/zh-TW/appengine/">app engine</a> <a href="http://code.google.com/intl/zh-TW/appengine/docs/python/gettingstarted/usingwebapp.html">webapp</a> 的 request handler get/post 分離有點感冒, 不過我想這是習慣問題吧, 所以後來都把 webapp 寫的東西都換成 django。</p>
<p>以前有看過一些文章說是把 django zip 起來, 然後<a href="http://code.google.com/intl/zh-TW/appengine/articles/django10_zipimport.html">用 zipimport 來跑 django</a>, 不過其實除非你要用的是 django trunk, 否則 app engine 其實本身就內建了 0.96, 1.0 跟 1.1, 當然這邊指的是雲的那一端, 本地端還是得裝上要使用的 django 版本, 不過不用把 django 放進你的 app engine project 就是了。</p>
<p>像是下面這段, 即使你使用的是 webapp, 你仍然可以透過下面這段 code, 寫在 request handler 的最前方, 來使用 django 1.1 的功能, 而非老舊的 django 0.96</p>
<pre><code>from google.appengine.dist import use_library
use_library('django', '1.1')
os.environ['DJANGO_SETTINGS_MODULE'] = 'myaudiocast.settings'</code></pre>
<p>至少 django 從 1.0 開始, template 的功能就大幅改進, 光 with 跟 escape_js 這兩個 template tag 就夠棒的了!</p>
<p>其實 google 「app engine django」就可以找到一堆教你如何在 app engine 使用 django 的文章, 不過我還是覺得 <a href="http://code.google.com/p/google-app-engine-django/">Google App Engine Helper for Django</a> 最方便。只需要下載下來解開, 幾乎不用修改就可以開始使用。</p>
<p>而 Google App Engine Helper for Django 預設是使用 django 1.0, 不過只要修改 main.py 裡, 下面這一段就可以使用 django 1.1 了</p>
<pre><code>InstallAppengineHelperForDjango('1.1')</code></pre>
<p>當然改用 django 1.0 以上的版本, 除了 template 之外就是 form 也改進了很多, 雖然原本 app engine 就已經有提供 djangoforms 可以直接透過 datastore 的 model 來產生 form, 但是在 webapp get/post request 分開處理的狀況下, django form 在使用上顯得非常憋腳, 而且 djangoforms 用的是 django 0.96 的 form, 所以功能上的確差了許多。</p>
<p>以上是我對在 app engine 上使用 django 的感想。</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2672/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>app engine datastore 效能心得</title>
		<link>http://tzangms.com/programming/2664</link>
		<comments>http://tzangms.com/programming/2664#comments</comments>
		<pubDate>Wed, 09 Jun 2010 17:29:20 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[datastore]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2664</guid>
		<description><![CDATA[由於這一陣子用 app engine 寫了一些玩具跟 myaudiocast, 所以來記錄一下心得。雖然 app engine 不用錢, 似乎不用怕資料庫 scale 的問題, 可是比起一般使用關聯式資料庫來說, 開始 run 之前得更仔細規劃, 因為有些資料在寫入後就無法更動了。 上面這張圖是 myaudiocast 簡單的示意圖, 接下來就用這張圖來說一下關於 datastore 使用上的心得 單筆資料 ( one-to-one ) 像是 User 對 Podcast 在我的規劃上是 one-to-one, 所以如果是 one-to-one 這類的資料就給定 key_name, 直接用 key_name 來抓單筆資料, 而不是先用 filter 之後在用 get 來取得單筆資料。 因為用 appstats 就發現後面這個方法常常是花最多時間的, 然而因為之前的資料都沒給 key_name 現在也來不及了 &#8230; 多筆資料 ( one-to-many, [...]]]></description>
			<content:encoded><![CDATA[<p>由於這一陣子用 <a href="http://code.google.com/intl/zh-TW/appengine/">app engine</a> 寫了一些玩具跟 <a href="http://www.myaudiocast.com">myaudiocast</a>, 所以來記錄一下心得。雖然 app engine 不用錢, 似乎不用怕資料庫 scale 的問題, 可是比起一般使用關聯式資料庫來說, 開始 run 之前得更仔細規劃, 因為有些資料在寫入後就無法更動了。</p>
<p><a href="http://tzangms.com/wp-content/uploads/2010/06/myaudiocast-model.jpg"><img class="aligncenter size-full wp-image-2669" title="myaudiocast-model" src="http://tzangms.com/wp-content/uploads/2010/06/myaudiocast-model.jpg" alt="" width="481" height="404" /></a></p>
<p>上面這張圖是 <a href="http://www.myaudiocast.com">myaudiocast</a> 簡單的示意圖, 接下來就用這張圖來說一下關於  datastore 使用上的心得</p>
<h2>單筆資料 ( one-to-one )</h2>
<p>像是 User 對 Podcast 在我的規劃上是 one-to-one, 所以如果是 one-to-one 這類的資料就給定 key_name, 直接用 key_name 來抓單筆資料, 而不是先用 filter 之後在用  get 來取得單筆資料。 因為用 appstats 就發現後面這個方法常常是花最多時間的, 然而因為之前的資料都沒給 key_name 現在也來不及了 &#8230;</p>
<h2>多筆資料 ( one-to-many, many-to-many )</h2>
<p>像是 Episode 這類 one-to-many, 會有多筆的資料, 沒事就不用給 key_name 了, 因為通常都是透過 filter 來取出多筆資料, 所以只需要寫入時指定 parent, 讓 user 的 episodes 可以成為一個 entity group, 這樣抓取資料比較快。</p>
<h2>盡量使用 memcache</h2>
<p>datastore 其實並沒有很快, 甚至 model api 沒有 query cache, 而 memcache 的 quota 其實滿大的, 所以要盡量用 memcache。</p>
<h2>避免在 template 透過關連取資料</h2>
<p>像是 podcast 跟 episodes 都可以透過關連, 像是 user.podcast 跟 user.episodes 來取得資料, 所以因為寫 django 的經驗, 我可能就直接丟 user 變數進 template, 然後都用 user.podcast, 跟 user.episodes 來取得資料, 可是這在 app engine 則是要避免的, 因為 app engine 的 model 並沒有 query cache, 所以可能會像下面這樣的作法, 就會對 podcast 做兩次 query。</p>
<pre><code>{{ user.podcast.title }}
{{ user.podcast.description }}</code></pre>
<p>所以得一開始就把 user 跟 podcast 丟進 template, 直接取得資料而不是透過物件關連。</p>
<p>不過有時候就是一定得透過關連來做, 那麼就請使用  django 1.0 以上的 template, 透過 <a href="http://docs.djangoproject.com/en/dev/ref/templates/builtins/#with">with</a> 這個 template tag 來避免多次 query, 或者是在 model 新增一個 property 然後用 memcache 來解決, 像是我的作法</p>
<pre><code>class User(db.Model):
    ...

    @property
    def podcast(self):
        cache_key = 'user-podcast-%s' % self.key()
        p = memcache.get(cache_key)
        if not p:
            p = self.podcasts.ancestor(self).get()
            memcache.add(cache_key, p)

        return p</code></pre>
<p>先前說過, 以前不懂忘記給 key_name, 現在只能這樣 query 了, 頂多加上個 ancestor (默)</p>
<h2>結論</h2>
<p>datastore 雖然不太需要擔心 scale 的問題, 可是在 run 之前卻得更仔細規劃, 否則效能低落, 花的只是更多錢阿 XD 而 memcache 則是一定得用, 否則跑起來的確是不夠快。 </p>
<p>大概是這樣, 希望沒有哪裡有寫錯的, 如果有的話, 也請多多留言指指教, 謝謝 :p</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2664/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>app engine 效能檢測</title>
		<link>http://tzangms.com/programming/2660</link>
		<comments>http://tzangms.com/programming/2660#comments</comments>
		<pubDate>Mon, 07 Jun 2010 13:37:53 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[appstats]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2660</guid>
		<description><![CDATA[先前 app engine 推出了 appstats, 一整個做的超好, 而且很簡單! 很容易就知道那邊吃掉比較多資源。 按照文件把 appstats 裝好 run 起來後, 就可以在 app engine 後台的 log 上看到 appstats 添加的 link, 如下圖反白的網址 連過去這個網址就可以看到下面這個 bar chart 在 bar chart 上點選一個比較長的 bar 就可以看到下圖, appstats 幫你把吃掉比較多資源的 code 給標出來 超方便的! 真的很容易找出程式慢在哪。]]></description>
			<content:encoded><![CDATA[<p>先前 <a href="http://code.google.com/intl/zh-TW/appengine/">app engine</a> 推出了 <a href="http://code.google.com/intl/zh-TW/appengine/docs/python/tools/appstats.html">appstats</a>, 一整個做的超好, 而且很簡單! 很容易就知道那邊吃掉比較多資源。</p>
<p>按照<a href="http://code.google.com/intl/zh-TW/appengine/docs/python/tools/appstats.html">文件</a>把 appstats 裝好 run 起來後, 就可以在 app engine 後台的 log 上看到 appstats 添加的 link, 如下圖反白的網址<br />
<a href="http://tzangms.com/wp-content/uploads/2010/06/appstats-log.jpg"><img src="http://tzangms.com/wp-content/uploads/2010/06/appstats-log-500x364.jpg" alt="" title="appstats-log" width="500" height="364" class="aligncenter size-large wp-image-2663" /></a></p>
<p>連過去這個網址就可以看到下面這個 bar chart<br />
<a href="http://tzangms.com/wp-content/uploads/2010/06/appstats-graph.jpg"><img src="http://tzangms.com/wp-content/uploads/2010/06/appstats-graph-500x288.jpg" alt="" title="appstats-graph" width="500" height="288" class="aligncenter size-large wp-image-2662" /></a></p>
<p>在 bar chart 上點選一個比較長的  bar 就可以看到下圖, appstats 幫你把吃掉比較多資源的 code 給標出來<br />
<a href="http://tzangms.com/wp-content/uploads/2010/06/appstats-code.jpg"><img src="http://tzangms.com/wp-content/uploads/2010/06/appstats-code-499x436.jpg" alt="" title="appstats-code" width="499" height="436" class="aligncenter size-large wp-image-2661" /></a></p>
<p>超方便的! 真的很容易找出程式慢在哪。</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2660/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MyAudioCast 新版型</title>
		<link>http://tzangms.com/music-related/2656</link>
		<comments>http://tzangms.com/music-related/2656#comments</comments>
		<pubDate>Sun, 30 May 2010 12:28:04 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Music]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[myaudiocast]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2656</guid>
		<description><![CDATA[這兩天都在改 MyAudioCast 的版型跟一些 code, 現在這樣看起來好多了 :D]]></description>
			<content:encoded><![CDATA[<p><a href="http://tzangms.com/wp-content/uploads/2010/05/MyAudioCast-輕鬆建立你自己的-Podcast.png"><img src="http://tzangms.com/wp-content/uploads/2010/05/MyAudioCast-輕鬆建立你自己的-Podcast-411x500.png" alt="" title="MyAudioCast - 輕鬆建立你自己的 Podcast!" width="411" height="500" class="aligncenter size-large wp-image-2655" /></a></p>
<p>這兩天都在改 <a href="http://www.myaudiocast.com/">MyAudioCast</a> 的版型跟一些 code, 現在這樣看起來好多了 :D</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/music-related/2656/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>透過 swfupload 直接上傳到 S3</title>
		<link>http://tzangms.com/programming/2649</link>
		<comments>http://tzangms.com/programming/2649#comments</comments>
		<pubDate>Wed, 12 May 2010 14:27:20 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[AppEngine]]></category>
		<category><![CDATA[blobstore]]></category>
		<category><![CDATA[s3]]></category>
		<category><![CDATA[swfupload]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2649</guid>
		<description><![CDATA[由於 app engine 無法上傳大檔案, 即使使用 BlobStore 單檔最大也只能到 50MB 而已, 對於 MyAudioCast 來說, 豬小草的 Podcast 檔案幾乎都是超過 100MB, 所以看來就只能用 S3 來放檔案, 可是 app engine 的 urlfetch 也只能傳 1MB, 所以後來就直接採用 S3 提供的 form upload 的方式, 直接用 HTML POST Form 把檔案送到 S3, 有興趣的話可以看看 Browser Uploads to S3 using HTML POST Forms 這一篇文章, 所以就可以不用透過後端程式, 直接從前端上傳檔案到 S3 然後 redirect 回來。所以在這邊記錄一下。 然而這樣出現了一個問題, [...]]]></description>
			<content:encoded><![CDATA[<p>由於 <a href="http://code.google.com/intl/zh-TW/appengine/">app engine</a> 無法上傳大檔案, 即使使用 <a href="http://tzangms.com/programming/2556">BlobStore</a> 單檔最大也只能到 50MB 而已, 對於 <a href="http://www.myaudiocast.com/">MyAudioCast</a> 來說, 豬小草的 Podcast 檔案幾乎都是超過 100MB, 所以看來就只能用 S3 來放檔案, 可是 app engine 的 urlfetch 也只能傳 1MB, 所以後來就直接採用 S3 提供的 form upload 的方式, 直接用 HTML POST Form 把檔案送到 S3, 有興趣的話可以看看 <a href="http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434">Browser Uploads to S3 using HTML POST Forms</a> 這一篇文章, 所以就可以不用透過後端程式, 直接從前端上傳檔案到 S3 然後 redirect 回來。所以在這邊記錄一下。</p>
<p>然而這樣出現了一個問題, 沒辦法檢查上傳的檔案類型, 甚至知道檔案大小 ( 原本的作法是上傳完之後, 再去 s3 抓檔案大小的資料 ), 所以研究了一下用 swfupload 來做檔案進度顯示以及顯示, 並限制檔案的類型、大小, 同時也可以取得檔案的大小。</p>
<p>原本的 POST FORM 看起來像是下面這樣</p>
<pre><code>&lt;form id="upload_form" action="http://myaudiocast.s3.amazonaws.com/"
    method="post" enctype="multipart/form-data"&gt;
&lt;input type="hidden" name="key" value="{{ key }}" /&gt;
&lt;input type="hidden" name="AWSAccessKeyId" value="{{ AWS_ACCESS_KEY }}" /&gt;
&lt;input type="hidden" name="acl" value="{{ acl }}" /&gt;
&lt;input type="hidden" name="policy" value="{{ policy }}" /&gt;
&lt;input type="hidden" name="signature" value="{{ signature }}" /&gt;
&lt;input type="hidden" name="Content-Type" value="{{ content_type }}" /&gt;
&lt;input type="hidden" name="Cache-Control" value="{{ cache_control }}" /&gt;
&lt;input type="hidden" name="Expires" value="{{ expires }}" /&gt;
&lt;input type="hidden" name="success_action_redirect" value="{{ success_action_redirect }}" /&gt;
...
&lt;/form&gt;</code></pre>
<p>基本上的作法就是把原本 policy conditions 當中的 success_action_redirect 改成 success_action_status, 也就是把轉址改成吐 201 的 status code, 然後在 policy conditions 移除 success_action_redirect, 並加上下面兩個項目即可。</p>
<pre><code>["starts-with", "$Filename", ""],
["eq", '$success_action_status', "201"]
</code></pre>
<p>而 swfupload 的 PostParams 也是把原本要 POST 出去的欄位加上即可</p>
<pre><code>swfu.setPostParams({
    'key': key,
    'AWSAccessKeyId': "{{ AWS_ACCESS_KEY }}",
    'acl': "{{ acl }}",
    'policy': "{{ policy }}",
    'signature': "{{ signature }}",
    'Content-Type': "{{ content_type }}",
    'Cache-Control': "{{ cache_control }}",
    'Expires': "{{ expires }}",
    'success_action_status': {{ success_action_status }}
});</code></pre>
<p>然後 s3 bucket 那邊也得加上一個 /crossdomain.xml, 否則 Flash 會有 security error, 檔案內容如下。</p>
<pre><code>&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE cross-domain-policy SYSTEM
    "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"&gt;
&lt;cross-domain-policy&gt;
    &lt;allow-access-from domain="*.myaudiocast.com" secure="false" /&gt;
&lt;/cross-domain-policy&gt;</code></pre>
<p><code> </code></p>
<p>最後就是, 由於 Flash 接到 200 以外的 status code 都會視為失敗 ( 至少我查到的資訊都是這麼說 ), 所以 swfupload 接到 201 的 status code 也是會認為失敗, 所以就得再 uploadError 這個 handler 判斷 status_code 是否為 201, 如果 201 則是上傳成功, 所以這點得再注意一下, 我目前的作法是這樣。</p>
<p>這篇主要只是記錄一下, S3 真是好服務, 而 app engine 也很好, 不過限制太多, 得自己繞路就是了 XD</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2649/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>新玩具封測</title>
		<link>http://tzangms.com/programming/2643</link>
		<comments>http://tzangms.com/programming/2643#comments</comments>
		<pubDate>Fri, 07 May 2010 16:20:59 +0000</pubDate>
		<dc:creator>tzangms</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[plurk]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://tzangms.com/?p=2643</guid>
		<description><![CDATA[之前在這一篇 寫到我在寫備份推特跟噗浪的工具, 其實說是備份有人可能會誤會, 其實不會備份你以前的訊息, 而是從現在開始幫你記錄你的推噗而已。 基本上是依我自己的需求來開發的, 記錄下來的推噗可以用每日以及日曆呈現, 然後可以搜尋, 以及用 hash tag 分類, 日曆的方式大概看起來像下面這樣 其實用來記錄推噗後, 可以回顧先前每天的訊息記錄, 可以很快就知道哪一天在幹嘛之類的, 就當成日記, 不過其實這也要看個人推噗的使用習慣啦。 另外透過 hash tag 來當書籤其實也滿好用的, 至少我自己覺得很不錯 XD 不過目前沒打算開放給太多人用, 畢竟有些人覺得沒這個需要, 所以有需要的人。 麻煩你在推特 follow 我, 並發送訊息下面這段訊息 小海 @tzangms 你好帥! 我要試用新玩具! 或者是 小海 @tzangms 我愛你! 我要試用新玩具! 甚至是你不想試用, 你也可以在你的推特發送下列訊息 小海 @tzangms 你超帥的! 我看到就會 DM 網址給你, 謝謝! XD]]></description>
			<content:encoded><![CDATA[<p>之前在<a href="http://tzangms.com/programming/2632">這一篇</a> 寫到我在寫備份推特跟噗浪的工具, 其實說是備份有人可能會誤會, 其實不會備份你以前的訊息, 而是從現在開始幫你記錄你的推噗而已。</p>
<p>基本上是依我自己的需求來開發的, 記錄下來的推噗可以用每日以及日曆呈現, 然後可以搜尋, 以及用 hash tag 分類, 日曆的方式大概看起來像下面這樣<br />
<a href="http://tzangms.com/wp-content/uploads/2010/05/螢幕快照-2010-05-07-下午11.49.01.png"><img src="http://tzangms.com/wp-content/uploads/2010/05/螢幕快照-2010-05-07-下午11.49.01-499x386.png" alt="" title="螢幕快照 2010-05-07 下午11.49.01" width="499" height="386" class="aligncenter size-large wp-image-2645" /></a></p>
<p>其實用來記錄推噗後, 可以回顧先前每天的訊息記錄, 可以很快就知道哪一天在幹嘛之類的, 就當成日記, 不過其實這也要看個人推噗的使用習慣啦。 另外透過 hash tag 來當書籤其實也滿好用的, 至少我自己覺得很不錯 XD</p>
<p>不過目前沒打算開放給太多人用, 畢竟有些人覺得沒這個需要, 所以有需要的人。 麻煩你在推特 follow 我, 並發送訊息下面這段訊息 </p>
<blockquote><p>小海 @tzangms 你好帥! 我要試用新玩具!</p></blockquote>
<p>或者是</p>
<blockquote><p>小海 @tzangms 我愛你! 我要試用新玩具!</p></blockquote>
<p>甚至是你不想試用, 你也可以在你的推特發送下列訊息</p>
<blockquote><p>小海 @tzangms 你超帥的! </p></blockquote>
<p>我看到就會 DM 網址給你, 謝謝! XD</p>
]]></content:encoded>
			<wfw:commentRss>http://tzangms.com/programming/2643/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
