Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

March 3, 2015

支付寶即時到帳串接小記

No comments:
先說個結論:要用公司的帳號透過工人智慧申請的方式去開通「即時到帳」,取得 PID 之後才能開發。開發階段沒有 sandbox 可用,要用真正的個人帳號以每次 0.01 元的消費方式來測試。當然財力雄厚的人,想要用 100 元也可以啦。

前些日子接到需求要接上支付寶的金流。在此之前我只有很爽地直接用 tka 接好的 paypal,測試的時候用一組測試卡號「盡量刷」,享受那種刷卡不用付錢的精神富裕。

這是頭一次接金流,還要用中國的支付寶。

我對支付寶的認識就是:「嗯,很大間的公司」,還要搜尋一下才能確認是馬雲的東西,我對馬雲最大的認識就是經常在 Facebook 看見他的照片及勉勵小語,好比「他媽的這根本不是我說的話」。

 接完了回頭看其實也沒啥,反正阿宅就是看完文件把路打通,每個人都會。只是一些準備工作比較讓人摸不著頭緒,這邊稍微紀錄一下,給需要的人一點幫助。

我接的金流是「即時到帳」(Direct Pay),在自家的網站上以 sign 過的資料產生一個 link,user 點下 link 之後就會被導到 alipay 的網站,在 alipay 登入 user 自己的帳戶之後就會看到對應的訂單,選擇付款之後,錢就會直接從 user 的帳戶轉到自己網站的帳戶。

假設你是一位要開發這個功能的技術宅,那麼你需要準備這些東西,有這些就能安心開發了
  • 一個可以付款的一般帳號
  • 一個可以收款,且申請了即時到帳功能的公司帳號,需要的帳戶資訊包括
    • seller email:就是這個公司帳號的 email
    • PID
    • Key
 request 都是送到 https://mapi.alipay.com/gateway.do,內容填什麼看文件就好了。



一開始連需要什麼功能都不知道,摸索了一下確定自己需要的是即時到帳。以為在這個飛機滿天飛,一堆人早上在台北吃早餐,中午在日本吃拉麵的年代,搜尋 "alipay api" 找到的支付寶開放平台以為就能開工,其實根本用不到。

因為 paypal 刷得很開心,以為 Sandbox 可以有相同體驗,後來才知道根本不行。

支付寶上頭找不到客服的 email,也許是國情不同,他們流行用線上客服。在上班時間排隊了一個小時之後終於轉到技術客服,還要用 cconv 轉成簡體發問

「我要開發即時到帳,一定要簽約完後才能開始開發嗎」『對』
「Sandbox 能用嗎?」『那個沒用,要用帳號每次消費 0.01 測試吧』

回頭想想不管是 Sandbox 或是 API website,都寫著「支付寶開放平台」,跟我要做的東西一點關係都沒有,是我自己充滿了過份美好的想像。

如果你是用 nodejs 開發的人,收 notification 的時候可能會遇到 req 沒有 body 的情況,請參考這篇 nodejs 集成支付宝能收到 notify 请求但收不到 notify 数据,也許是平常有牽老奶奶過馬路,這篇發問與解答正好出現在我撞牆的前一天,省去了很多冤枉時間。(具體錯在哪一行 code 我現在懶得找,歡迎大德補完)(如果是日本的金流我應該就會很認真找了 >/////<)

其實也就是那一篇讓我覺得:「啊,好險他們有寫,真感謝他們 <(_ _)>」。剛剛洗澡的時候也覺得自己也要來稍微整理一下,搞不好可以幫到哪位跟我一樣沒有頭緒的人:如果你的需求跟我一樣,那你只要/必須要準備好上面的東西,才能/就能放心開工了。

後來,Ly 說是 Paypal 比較先進,不是支付寶太落後,大部分的金流都跟支付寶一樣。

唉...

October 8, 2013

Livescript Backcall

No comments:
最近因緣際會之下開始碰 Livescript

原本好不容易把 Javascript 打通,以為可以開始用某種語言痛快說話時,突然又來了 Livescript,只好又開始牙牙學語

初碰 Livescript 總感覺到有無形的牆擋在前面,怎麼唸也不順,直到聽見高村長提到關鍵字「Perl」,心中好像有什麼結被打開了,與其把它當成某種 javascript 的變型,似乎把它當成 Perl 的變型要好一點,雖然原作者可能不這麼想 XD

心結打開就舒坦了一些

高村長又曾經開示 Livescript 重要的特色之一就是 backcall。如果沒有誤解,backcall 要解決的問題之一就是 javascript 可怕的 callback 地獄。以一段 pseudocode 來說

http.fetch_data(function(json) {
    open_file(function(filename) {
        save_to_file(filename, json);
    });
});

這段話可以如此解釋:從 http 取得一份資料,成功取得就打開檔案,然後把取得的資料存進檔案裡面。這些動作相當仰賴 callback,我們會一層又一層地將 function 物件傳進去,太多層就是 callback hell !!
用 Livescript 就可以透過 backcall 的方式這麼寫

json <- http.fetch_data
filename <- open_file
save_to_file filename, json

看起來比較簡潔,先來理解 backcall 的形式

callback_parameter <- caller_function
callback_body

箭頭的右側就是我們最先呼叫的 function,箭頭的左側則是傳入的 callback 參數,下方是 callback 的主體。也因此右側自成一組,左側與下方自成一組,看程式碼的時候就要這麼看它

json <- http.fetch_data
filename <- open_file
save_to_file filename, json


從形式上來看會是「執行 open_file 的 callback 是底下那一塊,左方是 callback 參數」。

既然要閱讀程式碼,就要能夠「唸」出來。我自己的念法就會是「http fetch data 之後就打開檔案,打開檔案之後就存入」,至於 parameters 的部份都忽略不看

update: 因為 callback chain 的關係,經常 callback 只會接受一個參數,也就是上一個 function call 的 return value。(不然就是再多一個 exception) 。在此前提下閱讀 backcall 就會簡單很多,上面的例子就是: http fetch data 的回傳值是 json,打開檔案回傳值是 filename,接著把 json 存進去 filename

這是我個人的理解方式,希望給同樣頭痛的人一點幫助

ps. 由於 backcall 底下都會是 callback body,若有不屬於 body 的 statements,用 do 就可以解決了

do
  json <- http.fetch_data
  filename <- open_file
  save_to_file filename, json
  this_is_in_callback \yeah

this_is_not_in_callback \yeah

December 27, 2012

在 Blogger 貼上程式碼

No comments:
在 blogger/blogspot 想要貼程式碼並且提供比較清晰的外觀,之前找到的方法不外乎幾種
  1. 把程式碼貼到一些 formatting tool,把程式碼轉成帶有顏色的 html code 之後再貼回 blogger
  2. 把 javascript 檔放到另外一個 host,開啟網頁的時候載入 js 檔對 source code 做修改
第一個方法我不是很喜歡,文章的原始檔變成一堆 html code 完全看不出文意。第二個方法比較貼近我的需求,可惜要額外載入一些 js 檔,我希望盡量保持簡單。

恰好最近學了一點點 js,自己動手做很簡單的 pretty code。先定義幾個 css 格式,網頁下載完成之後,透過 javascript 對於帶有 code 類別的 pre 區塊做修改。

修改的邏輯也很簡單,僅僅只是用 regular expression 找出一些定義好的字串上點顏色罷了。我也不常貼上太多程式碼,因此正規表示式沒有寫得很認真,剛好我夠用而已。

使用方法

貼上程式碼的時候為 pre 加上類別 code 即可,好比
<pre class="code">
int main(void) {
    printf("blah\n"); 
}
</pre>

會變成
int main(void) {
    printf("blah\n")
}

設定方法

打開 blogspot 的設計,直接編輯 html,在 css 的部份加上這一塊

pre {
margin: 5px 20px;
border: 1px dashed #666;
padding: 5px;
color: #000;
background: #f8f8f8;
white-space: pre-wrap;       /* css-3 */
white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
white-space: -pre-wrap;      /* Opera 4-6 */
white-space: -o-pre-wrap;    /* Opera 7 */
word-wrap: break-word;       /* Internet Explorer 5.5+ */
}
span.control{
font-weight: bold;
color: #A00;
}
span.type {
font-weight: bold;
color: #0A0;
}
span.literal {
color: #00C;
}
span.comment {
font-weight: bold;
color: #AAA;
}

接下來找到 javascript 的區塊貼上程式碼,請注意「這一塊不能直接貼上」,這邊是看網頁原始碼的時候看到的結果。真正要貼上的是底下那一塊

onload = function () {
    var elmts,
        count = 0,
        regLiteral = /(('.*?'|".*?"))/g, // 'foo' or "foo"
        regType = /(\W|)(void|int|float|double|byte|struct)(\W)/g, // int foo
        regControl = /(\W|)(for|if|fi|while|do|done|return|each)(\W)/g, // while()
        regClearCmt = /(\/\*.*?)()(.*?)(<\/span>)/g,
        regClearCmts = /(\/\/.*?)()(.*?)(<\/span>)/g,
        regCmtsStart = /\/\*/g, //for /*
        regCmtsEnd = /\*\//g,   //for  */
        regCmt = /\/\/(.*)/g,   //for  //

        replaceLtGt = function (pre) {
            var text = pre.innerHTML;
            // <a> to &lt;a&gt;
            pre.innerHTML = text.replace(/<(.+?)>/gi, "<$1>");
        },

        setColor = function (pre) {
            var text = pre.innerHTML;

            text = text.replace(regLiteral, "$1");
            text = text.replace(regType, "$1$2$3");
            text = text.replace(regControl, "$1$2$3");
            text = text.replace(regClearCmt, "$1$3");
            text = text.replace(regClearCmts, "$1$3");
            text = text.replace(regCmtsStart, "/*");
            text = text.replace(regCmtsEnd, "*/");
            text = text.replace(regCmt, "//$1");
            pre.innerHTML = text;
        };

    elmts = document.querySelectorAll("pre.code"),
    count = elmts && elmts.length;
    while (count > 0) {
        count--;
        replaceLtGt(elmts[count]);
        setColor(elmts[count]);
    }
};


因為貼上的對象是 blogger 的 template,因此要把 & 或 < 或 > 再做一次轉換,實際上真正要貼進 blogger 的 js code 是這一段(看不懂了吧!所以我才要先貼上面比較有人性的部份XD)

onload = function () {
    var elmts,
        count = 0,
        regLiteral = /((&#39;.*?&#39;|&quot;.*?&quot;))/g, // &#39;foo&#39; or &quot;foo&quot;
        regType = /(\W|)(void|int|float|double|byte|struct)(\W)/g, // int foo
        regControl = /(\W|)(for|if|fi|while|do|done|return|each)(\W)/g, // while()
        regClearCmt = /(\/\*.*?)(&lt;span class=&quot;.*?&quot;&gt;)(.*?)(&lt;\/span&gt;)/g,
        regClearCmts = /(\/\/.*?)(&lt;span class=&quot;.*?&quot;&gt;)(.*?)(&lt;\/span&gt;)/g,
        regCmtsStart = /\/\*/g, //for /*
        regCmtsEnd = /\*\//g,   //for  */
        regCmt = /\/\/(.*)/g,   //for  //

        replaceLtGt = function (pre) {
            var text = pre.innerHTML;
            // &lt;a&gt; to &amp;lt;a&amp;gt;
            pre.innerHTML = text.replace(/&lt;(.+?)&gt;/gi, &quot;&amp;lt;$1&amp;gt;&quot;);
        },

        setColor = function (pre) {
            var text = pre.innerHTML;

            text = text.replace(regLiteral, &quot;&lt;span class=\&quot;literal\&quot;&gt;$1&lt;/span&gt;&quot;);
            text = text.replace(regType, &quot;$1&lt;span class=\&quot;type\&quot;&gt;$2&lt;/span&gt;$3&quot;);
            text = text.replace(regControl, &quot;$1&lt;span class=\&quot;control\&quot;&gt;$2&lt;/span&gt;$3&quot;);
            text = text.replace(regClearCmt, &quot;$1$3&quot;);
            text = text.replace(regClearCmts, &quot;$1$3&quot;);
            text = text.replace(regCmtsStart, &quot;&lt;span class=\&quot;comment\&quot;&gt;/*&quot;);
            text = text.replace(regCmtsEnd, &quot;*/&lt;/span&gt;&quot;);
            text = text.replace(regCmt, &quot;&lt;span class=\&quot;comment\&quot;&gt;//$1&lt;/span&gt;&quot;);
            pre.innerHTML = text;
        };

    elmts = document.querySelectorAll(&quot;pre.code&quot;),
    count = elmts &amp;&amp; elmts.length;
    while (count &gt; 0) {
        count--;
        replaceLtGt(elmts[count]);
        setColor(elmts[count]);
    }

};
要把「貼上 template 的醜陋內容再轉一次變成能夠貼上 blog 文章」這樣轉來轉去自己都快被搞混了,希望我沒有貼錯

December 19, 2012

Javascript 的 Object 與 Function

No comments:
雖然說只要翻兩下書看幾個網站就能開始寫 code,而且看了這些東西也不見得對於寫程式有一日千里的幫助。出於阿宅很純粹的好奇心,我還是花了點時間看了 ECMAScript  Q___Q

程式寫了一段時間,有時會對某一句天經地義的話沉思很久,總感覺此中有真意,欲辯「不知言」 - 不知道該怎麼解釋它,當然也有可能是庸人自擾,痴人發夢。往往好奇心就在此時被挑起,追尋了半天終於得到了一個原本就知道而且跟大家一模一樣的結論。或許此時只能用「過程比結果重要」來安慰自己。

從來沒想過自己會寫 javascript,剛碰 javascript 就讀到了不少讓人「津津樂道」的特色。好比 Hoisting 或 Closure 這種沒有在 spec 裡面出現,而是在實務中衍生出來的概念,又或著惡名昭彰的全域變數,一不小心就會跟它打上交道,看到不少說法都是因為 spec 定得不好。

這就有意思了,究竟是什麼樣的 spec 可以把一個語言搞成這樣?平常會用觀察的方式去理解一個語言的行為,但是 Javascript 的「出名」讓我有點擔憂,害怕自己觀察到的是某一個實作獨有的現象。因此才會去翻 ECMAScript 順便滿足好奇心。

好奇心被挑起之後,想要釐清以下幾個問題
  • 什麼叫做物件
  • 什麼叫做 function
  • 什麼是 function call, new,constructor
  • 產生新物件的過程為何
  • 產生的新物件與 constructor 的關係為何
在開始之前先說明,built-in 的 function 或 property, object 會以 [[Something]] 來表示,如果沒有理解錯誤,[[Prototype]] 就是實作中經常看見的 __proto__ 這個 property。

接下來是一點閱讀的心得與筆記,若有疏誤請不吝指教

4.2 Language Overview

4.2 指的是 spec 裡面的 4.2 章節,後面還會重複出現類似的數字。

在 Overview 的部份對一些常見且富含多種意義的名詞做了稍微明確解釋,先記起這些名詞往後會比較順利

  • ECMAScript program
    一群可以相互溝通的物件(is a cluster of communicating objects),程式就是在物件的互動之中完成功能。
  • ECMAScript object
  • 帶有一些 properties 的集合。(is a collection of properties each with zero or more attributes that determine how each property can be used)
  • Properties
    容器,可保有物件、函式或是 primitive value(are containers that hold other objects, primitive values, or functions.)
  • Primitive value
    • Undefined
    • Null
    • Boolean
    • Number
    • String
  • Object
    內建型別 Object 的成員(is a member of the remaining built-in type Object)
  • Function
  • 可以呼叫的 object (is a callable object.)
  • Method
    物件的 property 如果是個 function,稱之為 method(A function that is associated with an object via a property.)
而且 ECMAScript 定義了一組的 built-in objects
  • Object object
  • Function object
  • Array object
  • String object
  • Boolean object
  • Number object
  • Math object
  • Date object
  • RegExp object
  • JSON object
  • Error object
    • Error
    • EvalError
    • RangeError
    • ReferenceError
    • SyntaxError
    • TypeError
    • URIError
所謂的物件,就是 properties 的 collection。property 的概念上就像是 pointer,也就是說物件就是帶有一堆 pointer 的資料結構,這個 property 可能會指向 primitive value, function, object。

8.6.2 Object Internal Properties and Methods

這一章節指出,所有的物件都一定帶有某些 internal properties,這邊僅列出幾項
  • [[Prototype]]
  • [[Class]]
  • [[Get]]
  • [[GetOwnProperties]]
[[Class]] 為例,這個 property 會指向一個 String,表示「這是一個什麼樣的物件」,結果可能會是 Array, JSON, Object 或是 Function。

[[Get]] 指向一個 internal method,這個 method 需要一個參數叫 propertyName,執行的結果是回傳一個 property 的 value。

[[Prototype]] 就是 __proto__,至於它的值後面再說明。

此外,某些物件還有這些 internal properties
  • [[Constructor]] new operator 會用這個 property
  • [[Call]] 單純的 function call 會使用這個 property
  • [[Code]] 只有 Function Object 會有這個屬性
這些就是 Function Object 的 internal properties,至此終於知道「Function 也是 Object」這句話的意義:Function object 就是比 Object object 多了一些特定 internal properties 的物件。

接下來更深入地看一下產生 Function object 的過程

13.2 Creating Function Object

先定義名詞
    • FormalParameterList - 參數 list
    • FunctionBody - function 的內容
    Function object 產生的過程是
    1. 產生 native ECMASCript object, 令其名為 F
    2. 除了 [[Get]] 之外設定所有的 internal methods
    3. 把 F 的 internal property [[Class]] 設成 "Function"
    4. 把 F 的 internal property [[Prototype]] 設成 Function.prototype,即 built-in object Function 的prototype 屬性所指向的物件
    5. [[Code]] 設成 FunctionBody
    6. 設定許多 internal properties,其中一些 property 會指向特定的 internal method,以下這兩個與 function 的行為有關
      • internal method [[Call]] 被 invoke 時這一次執行的狀態放入 funcCtx。[[Code]] 這個 internal property 就是 FunctionBody,執行之後的結果回傳,且把之前的執行狀態 restore 回來。
      • internal method [[Constructor]] 被 invoke 時
        1. 產生新的 ECMAScript object(假設叫 obj),並且設定一些 internal methods。
        2. 把 obj 的 [[Class]] 設成 "Object"
        3. 對 F 呼叫 [[Get]] property,參數是 "prototype",假設呼叫的結果叫做 proto
        4. 如果 proto 是一個 Object,把 obj 的 [[Prototype]] 指向該物件
        5. 如果 proto 不是一個 Object,把 obj 的 [[Prototype]] 指向 built-in Object 的 prototype 屬性
        6. 回傳值是 invoke [[Call]] 的結果並且把 this 指向新產生的 Obj 。因為 [[Call]] 其實是執行 Code,所以Constructor 與 Call 都同樣是去跑一遍 Code
    Function 也是物件,只是這個物件帶的屬性有點不一樣,因此成為一個可以呼叫(callable)的物件。

    產生 Function object 的時候,也會並為該物件設定一些 properties。好比把 [[Call]], [[Constructor]] [[Code]]。Code 的內容是 FunctionBody,[[Call]] 跟 [[Constructor]] 指向 internal method。

    執行這個 function 的時候(call function),就會 invoke [[Call]],[[Call]] 指向了 built-in function,作用是拿 [[Code]] 的值來執行。

    如果用 new 來執行 function,就會 invoke [[Constructor]]。spec 說 [[Constructor]] 也會去 inkvoke [[Call]],但是多了一些動作,譬如說設定 prototype,而且在 invocke [[Call]] 的時候會把 'this' 指到一開始產生的物件。

    所以 new 跟平常的 function call 各自執行不同的 internal method,前者會多做一些事情,譬如說把 this 指向剛剛產生的物件,以及設定 prototype。

    prototype property 跟 [[Prototype]] 是不一樣的東西。*.prototype 僅是一個 property,它什麼都可以指。而 [[Prototype]] 是 internal property,會指向 Constructor 的 prototype property,或是內建物件的 prototype property,總之就是會指向某一個物件,查找 property 的時候才有一個 chain 可以用。謹記這兩者的分別,閱讀 jQuery core 的時候會有幫助。