2018年10月6日 星期六

【AS400】COBOL REWRITE FILE

若想要寫 Cobol 變更 Physical File 的資料
  1. 檔案開啟模式須為 I-O
  2. * Update Data 
    REWRITE FILE-REC
    
  3. 另外需要注意的是,若要變更 KEY 值,先讀取舊 KEY 值資料,並給予新的 KEY 值。 此方法會 REWRITE 失敗,File Status 錯誤訊息為 23
  4. 只能 DELETE 舊 KEY 值資料,並 WRITE 新 KEY 值資料
  5. 由 Record Not Found 的錯誤訊息推論,執行 REWRITE 之前並不需要先 READ FILE,只需要先給定 KEY 值即可

2017年8月25日 星期五

【AS400】Physical File 基本概念


  1. Physical File 與 Logical File 皆為 AS 400 的 Database File
  2. Physical File 的 Source File 描述檔案結構,與 Table Schema 相似
  3. PF 的 Source Compile 之後,會產生 Type 為 *FILE 的 Object,實際存放資料
    • Type is PF:Defining a PF using DDS
    • Type is *FILE:Saving Data
  4. 有資料的 PF 再次 Compile 之後,原先資料會遺失
  5. 若要變更 PF 的 Field Attribute ,可使用 CHGPF 指令,無論是否有資料。但有其限制
    • 成功:增加欄位長度、新增欄位、新增或刪除鍵值、變更欄位順序、更名 Column Heading、更名 Alias
    • 資料遺失:縮減欄位長度、移除欄位、更名 Field Name
    • 失敗:將欄位型態由文字轉數字或數字轉文字、資料為亂碼 (ex:++++)
    • * Change Physical File (CHGPF)
      CHGPF FILE(LIB/OBJ) SRCFILE(LIB/QDBFSRC) SRCMBR(OBJ_SRC)
      
  6. 若 DSPF 同時產生於 Data Lib 與 Program Lib 之下
    • 當程式於執行階段 OPEN 該 DSPF 時,會發生 File Status = 39 Exception
    • 執行 dspjoblog 查詢錯誤訊息,會顯示該 DSPF 發生 Level Check 之錯誤

2017年8月12日 星期六

【NetBeans】環境設定二三事


  1. 版本是否為最新版
  2. JRE 和 JDK 是否安裝
  3. 專案需要 Library 是否 import
  4. NetBeans 某一版更新會失敗,若無法成功開啟,請斷網

2016年12月15日 星期四

【Git】basic command

$ git checkout -b debug
Switched to a new branch 'debug'
$ git checkout master
Switched to branch 'master'
$ git merge debug
將 debug 分支合併回 master
$ git branch -d debug
Deleted branch debug. $ git commit -m "commit message" 改變指標 $ git reset 會移動分支 $ git log 秀出分支的頭到尾

2015年5月29日 星期五

【CentOS】rsync 異地備援

需求為有四台機器 ( OS:Linux CentOS )
Master A, Client B, Client C, Client D
Master A 為有版控的開發環境
希望 commit 到 Master A 後
能夠自動同步到三台 Client 機器上

Linux 有一個很好用的異地備援指令 rsync
rsync 第一次做完 Full Backup 後
日後備份檔案會是採取差異備份的策略
大幅降低備份檔案的傳輸時間
rsync 有兩種方法在 server / client 進行傳輸
1. 透過 ssh 的通道
2. 使用 rsync 提供的 daemon 服務
採用方法一透過 ssh 的通道來同步檔案
由於希望往後能靠自動排程(crontab)來進行同步
所以需要先製作出免密碼登入的 ssh 金鑰

ssh 遠端登入免密碼
  1. 在 Master 端建立 Public Key 與 Private Key
  2. Private Key 保存於 Master A
  3. Public Key 傳送給 Client B,C,D
#用 RSA 演算法產生 Key Pair
ssh-keygen -t rsa
#查看 keys
ll ~/.ssh
#Private Key 預設位置不用變更
#Public Key to Client B
scp id_rsa.pub root@clientB:~/.ssh
#Public Key to Client C
scp id_rsa.pub root@clientC:~/.ssh
#Public Key to Client D
scp ip_rsa.pub root@clientD:~/.ssh


接下來到三台 Client 端
將 Public Key 保存至 authorized_keys
完成後,ssh 登入 Client 就免密碼
cd ~/.ssh
cat id_rsa.pub >> authorized_keys
chmod 644 authorized_keys


將備份流程寫入 backup.sh 檔案
#!/bin/bash
# Master A 檔案路徑
localdir="/local/path"
# Client 端備份路徑
backupdir="/backups"
# Client 端 ip 位址
remoteip="192.168.100.252 192.168.100.253 192.168.100.254"
for ip in ${remoteip}
do
    rsync -av ${localdir} -e ssh root@${ip}:${backupdir}
done
# 建立 crontab 工作,每十五分鐘差異備份一次
crontab -e
0-59/15 * * * * sh backup.sh

2015年2月5日 星期四

【Ubuntu】crontab 刪除過期備份檔案

之前有寫過 crontab 排程 postgreSQL 自動備份
若沒有自動清除老舊的備份檔案
就會累積不少備份檔案
因此修改一下之前寫的 backup.sh 檔案
假設備份檔案保留三個月
#設定刪除日期
deldate=$(date -d'3 months ago' +%Y%m%d)
#刪除三個月前備份檔案
rm -f postgres."$deldate".tar.gz
設定刪除日期的地方
若是要刪除五天前的檔案
可修改為 '5 days ago'
若有需要修改自動排程
cd /etc
vi crontab
若要手動刪除過期備份檔案
可以善用 find 指令
find /path/to -mtime +5 -exec rm {} \;
-mtime 表示最後修改時間
+5 表示五天以前
-exec 接要執行的指令
{} 表示 find 指令找到的檔案

2015年1月13日 星期二

【Javascript】匯出 csv

將 table 的內容匯出成 csv 檔案
利用 encodeURIComponent
將字串轉為 Data URI
但要注意轉出的 code 為 UTF-8 編碼
若直接用 Microsoft Office Excel 開啟 csv 檔案時
中文會變成亂碼
因為 Excel 無法預設讀取 UTF-8 編碼的 CSV 檔案
所以利用增加 UTF-8 BOM 的方式
讓 Excel 直接開啟 csv 不會出現亂碼
navigator.appVersion.indexOf("Win") 若回傳值不為 -1
表示 OS 為 Windows 系列
指定 charset 為 帶 BOM 的 UTF-8

產生 CSV 內容的資料處理部分
傳入的參數 _csvString
除了每列資料要加斷行符號
不同欄位之間的資料要加逗號之外
還要額外處理兩個地方
1.資料若含有特殊符號,例如逗號,資料需加上雙引號
2.資料內容若已有雙引號,建議用 replace 取代為兩個雙引號
這樣用 Excel 開啟時,瀏覽效果較佳
function exportToCSV( _csvString ) {
    var downloadLink = document.createElement("a");
    downloadLink.download = "dataTable.csv";
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null) {
        var code = encodeURIComponent( _csvString );
        if ( navigator.appVersion.indexOf("Win")==-1 ) {
            downloadLink.href = "data:application/csv;charset=utf-8," + code;
        } else {
            downloadLink.href = "data:application/csv;charset=utf-8,%EF%BB%BF" + code;
        }
    }

    downloadLink.click();
}

2015年1月8日 星期四

【Javascript】匯出txt


因為有將 Log 直接寫進 html 裡面
所以就想說將網頁上的純文字內容輸出為一個 txt 檔案
saveTextAsFile function 內有兩個參數
第一個參數 _fileName 為預設在本地端存檔的檔名
第二個參數 _text 為輸出的純文字內容

function saveTextAsFile( _fileName, _text ) {
    var textFileAsBlob = new Blob([_text], {type:'text/plain'});

    var downloadLink = document.createElement("a");
    downloadLink.download = _fileName;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null) {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    } else {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}

function destroyClickedElement(event) {
    document.body.removeChild(event.target);
}

2014年9月24日 星期三

【Ubuntu】postgreSQL 本地備份

以下文章所出現家目錄,為安裝 PostgreSQL 的帳號之家目錄
例如是使用 user 帳號安裝 PostgreSQL
在家目錄新增檔案 .pgpass
檔案內容只有一行
localhost:port:database:username:password
localhost: 輸入 ip;若為本機端,輸入 127.0.0.1
port: port of PostgreSQL
database: 資料庫名稱
username: 資料庫帳號
password: 資料庫密碼

修改 .pgpass 的權限為 600
sudo chmod 600 .pgpass

新增備份目錄,測試匯出資料庫是否不用輸入密碼,若不用則上述設定成功
mkdir dbbackup
pg_dump -h 127.0.0.1 -p 5432 -U postgres postgres>postgres.dump

在家目錄新增檔案 backupdb.sh ,檔案內容如下
#!/bin/bash

#設定時間變數
day=$(date +%Y%m%d)
#設定備份路徑
bkdir="/home/user/dbbackup"
#備份資料庫
pg_dump -h 127.0.0.1 -p 5432 -U postgres postgres>"$bkdir"/postgres.dump
#移動到備份目錄
cd "$bkdir"
#壓縮資料庫並加上日期
tar -zcf postgres."$day".tar.gz postgres.dump
#刪除備份檔
rm postgres.dump

exit 0
加入 crontab 排程內,每天凌晨3:30做備份
30 3 * * * user sh /home/user/backupdb.sh
若要將 tar 打包好的備份檔案解壓縮,指令如下
tar -zxv -f postgres.20140924.tar.gz

2014年8月28日 星期四

【Node.js】Send Email

需求為寄出帳號認證信件
開發環境為 ubuntu, nodejs, express, smtp server
以及需要安裝兩個 nodejs 模組
nodemailer 與 nodemailer-smtp-transport
使用 npm 安裝
  1. npm install nodemailer
  2. npm install nodemailer-smtp-transport
module.exports = {
 sendEmail: function(_recipient, _subject, _html, _callback) {
  var nodemailer = require('nodemailer');
  var smtpTransport = require('nodemailer-smtp-transport');
  var config = require("../config/config");
     var transporter = nodemailer.createTransport(smtpTransport({
         host: config.smtp.host,
         port: config.smtp.port,
         auth: {
             user: config.smtp.user,
             pass: config.smtp.pwd
         }
     }));

     transporter.sendMail({
         from: 'sender@domain.org.tw',
         to: _recipient,
         subject: _subject,
         html: _html
     }, function(err, info) {
         _callback(err, info);
     });
 }
}
使用 SMTP Server 的好處是
寄件人的位置可以自行定義
若不介意寄件人地址
也可以請 Gmail 幫忙寄信
更改 transporter 即可
var transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
        user: 'sender@gmail.com',
        pass: 'password'
    }
});

2014年8月20日 星期三

【Ubuntu】設定開機後啟動服務

用 forever 監控 nodejs 服務
但是當 ubuntu 重啟後
forever 並不會重啟原本監控中的服務
導致監控中的 nodejs 服務中斷
因此編輯 shell script 設定 ubuntu 重啟後
forever 重新監控 nodejs 服務

在 ubuntu 路徑 /etc/init.d 下,
增加 run_forever.sh
************檔案內容開始************

forever start /var/nodejs/app.js

************檔案內容結束************

編輯完 shell script 後
還需要執行以下兩個指令

  1. sudo update-rc.d run_forever.sh defaults 99 1
  2. sudo chmod +x /etc/init.d/run_forever.sh*

最後重開機做測試,重開機指令
sudo reboot
重啟 ubuntu 之後,可用 forever list 指令觀察 nodejs 是否有執行服務

2014年6月27日 星期五

【Apache2 in Ubuntu】Host a node.js site through apache

目的:在單一 ip 上的相同 port 運行 apache 與 nodejs 服務
之所以會那麼麻煩,是因為 Apache2 in Ubuntu 所在的 ip 位置
對外服務只開放 80 port
所以才想要在單一 port 上 run apache2 與 node.js
步驟如下:
  1. install mod_proxy and mod_proxy_http
  2. update apache2 conf
  3. run node.js app
  4. restart apache2 service
  • install mod_proxy
    1. sudo apt-get install libapache2-mod-proxy-html
    2. apt-get install libxml2-dev
    3. a2enmod proxy proxy_http

  • update apache2 conf
    1. vi /etc/apache2/site-available/000-default.conf
    2. 編輯 conf 檔案,加入以下數行 code
    3. <Virtual *:80>
          ProxyRequests off
       
          <Proxy *>
              Order deny,allow
              Allow from all
          </Proxy*>
       
          ProxyPass /api http://localhost:2368
          ProxyPassReverse /api http://localhost:2368
      </Virtual>
      

  • run node.js app
    1. app.js 程式碼如下:
    2. var express = require('express');
      var app = express();
      app.get('/', function(req, res) {
          res.send("Welcome nodejs and express app api");    
      });
      app.listen(2368);
      
    3. forever start app.js(須先安裝 forever 套件)

  • restart apache2 service
    1. service apache2 reload
    2. service apache2 restart
重啟 apache 服務後
這樣連線 www.servername.com.tw 就會連到 apache index.html
而連線 www.servername.com.tw/api 則 apache 會將 request 導向 nodejs 服務
這個方法可以保持 80 port 對外,但 /api 則可以送出 request 至 node.js 監聽的 port

2014年4月15日 星期二

【jQuery】Remove item from json array

var jsonArray = [
    {name: 'Alice', id: 001},
    {name: 'Bob', id: 002},
    {name: 'Namei', id: 003}
];

假設想刪除 jsonArray 其中一個 json 物件, 該如何實作?

function findAndRemove(array, property, value) {
    for (var key in array) {
        if (array[key][property] == value) {
            array.splice(key, 1);
        }
    }
}
/* remove a json object with property of 'name' whose value is 'Namei' */
findAndRemove(jsonArray, 'name', 'Namei');

splice 為 JavaScript Array 的一個 Method
定義為: The splice() method adds/removes items to/from an array, and returns the removed item(s).
Add's Parameter: array.splice(index, howmany, item1, ....., itemX)
index 指定插入元素於陣列的位置; howmany 插入多少元素; item 為插入元素
Remove's Parameter: array.splice(index, howmany)
index 若為負值,則表示距離陣列尾端的位置; howmany: If set to 0, no items will be removed.

2014年4月7日 星期一

【CSS】:nth-child v.s. jQuery:eq

之前沒研究清楚,
誤以為 CSS's :nth-child  跟 jQuery's :eq
兩者的 selector 是相同效果,
但其實這兩者之間定義不完全相同。

先來看看 jQuery's :eq( index ) 的定義,
Reduce the set of matched elements to the one at the specified index.
如果 index 為正值,則是以 0 對映到首個element;
   index 為負值,則從最後一個element計數。

再來看看 CSS's :nth-child( n ) 的定義,
The :nth-child(n) selector matches every element that is the nth child, regardless of type, of its parent.
n can be a number, a keyword, or a formula.
差異在於 CSS 會先找其parent的所有child element,再判斷是否符合條件。

舉例而言:
<div>
    <p>This is a heading</p>
    <div id="one" class="foo"></div>
    <div id="two" class="foo"></div>
    <div id="three" class="foo"></div>
</div>
以CSS Syntax來講, .foo:nth-child(2) 會找到 div#one ,
因為 #one 是容器內第二個元素,類別也符合條件。
但若 .foo:nth-child(1) 則找不到符合的元素,
因為容器內第一個元素是 p tag ,但卻不符合類別的條件。
補充 jQuery's :nth-child 定義,
Selects all elements that are the nth-child of their parent.
另外 jQuery's implementation of :nth- selectors is strictly derived from the CSS specification
所以 jQuery's :eq 只回傳第一個符合條件的元素;
而 jQuery's :nth-child 則會回傳所有符合條件的元素。

2014年1月16日 星期四

【Javascript】Array sort() Method

  1. 內建 Array sort
  2. var fruits = ["Banana", "Orange", "Apple", "Mango"];
    fruits.sort();
    // output is Apple,Banana,Mango,Orange
    
  3. 內建 reverse
  4. var fruits = ["Banana", "Orange", "Apple", "Mango"];
    fruits.sort();
    fruits.reverse();
    // output is Orange,Mango,Banana,Apple
    
  5. Sort numbers (numerically and ascending)
  6. var points = [40,100,1,5,25,10];
    points.sort(function(a,b){return a-b});
    // output is 1,5,10,25,40,100
    
  7. Sort numbers (alphabetically and descending)
  8. var points = [40,100,1,5,25,10];
    points.sort(function(a,b){return b-a});
    // output is 100,40,25,10,5,1
    
    ##### 上述例子為 w3shools Example #####
    ##### 以下是 object sort method #####

  9. object sort numbers
  10. var student = [{name: "Tom", score: 80}
    , {name: "Mary", score: 70}
    , {name: "Cathy", score: 90}];
    student.sort(function(a,b){return a.score-b.score});
    // output is [{name: "Mary", score: 70}, 
    // {name: "Tom", score: 80}, 
    // {name: "Cathy", score: 90}]
    
  11. object sort alphabetically
  12. var student = [{name: "Tom", score: 80}
    , {name: "Mary", score: 70}
    , {name: "Cathy", score: 90}];
    student.sort(function(a,b){return a.name > b.name});
    // output is [{name: "Cathy", score: 90}, 
    // {name: "Mary", score: 70},
    // {name: "Tom", score: 80}]
    

2013年12月26日 星期四

【jQuery】keyup event v.s. keypress event

目的:檔案命名時,限制某些字元無法輸入!

限制字元: \ / | ? :

在此種情況下,使用 keypress 事件較為合適
keydown event 會判斷是鍵盤上哪個鍵被按下,
而 keypress event 則會判斷是哪個字元被輸入
舉例來說,輸入小寫字元 "a",
keypress 事件會回傳 97
keydown 事件回傳 65
輸入大寫字元 "A",
keypress 事件回傳 65
keydown 事件回傳 65
由上例可知, keypress 可以準確分辨大寫 "A" 與小寫 "a",
而 keydwon 則因為回傳皆為 65,無法辨識輸入字元為大寫 "A" 或是 小寫 "a"
但 keydown event 能夠偵測某些特殊按鍵,像是 Shift 或是 方向鍵

在本例中,因為希望限制 : 輸入,而 ; 則可以正常輸入
使用 keydown event,則 event.which 值皆為 186
使用 keypress event, ; reported as 59, : reported as 58
所以 keypress event 會較符合此次限制檔案命名需求!

2013年12月2日 星期一

【jQuery】Trigger keyup event

需求:刪除檔案可以點擊"刪除"圖示或是按下鍵盤上"DEL"按鍵

實作:因為兩個方式都是實作刪除檔案,所以可以先寫好其中一個 function,
另一個就直接觸發該 function 即可。

想法:先實作出使用"DEL"鍵刪除;點擊 Icon 則模擬鍵盤事件即可。

$('item').keyup(function(event) {
    if (event.which == 46) {
        // to do delete file
    }
});

$('.icon').click({
    var e = $.Event('keyup');
    e.which = 46; // Delete
    $('item').trigger(e);
});

另外要注意的是,一般 html tag (ex:div) 需要加上 tabindex 屬性才可以觸發鍵盤事件
而 input tag 則不需要額外加上 tabindex 屬性

2013年11月29日 星期五

【Javascript】XMLHttpRequest 解決 Cross Domain 檔案下載

需求為 Frontend.js 與 實際檔案放置在不同主機上,
所以需要解決 Cross Domain 資料存取的限制。

解決辦法為採用 XMLHttpRequest 物件來突破跨區存取限制。
直接看 Code
downloadFile = function( _fileUrl ) {
    var xhr = new XMLHttpRequest();

    if ("withCredentials" in xhr) {
        xhr.open('GET', _fileUrl, true);
    }    
    else if (typeof XDomainRequest != "undefined") {
        xhr = new XDomainRequest();
        xhr.open('GET', _fileUrl );
    }
        
    xhr.responseType = "blob";
    xhr.onreadystatechange = function () { 
        if (xhr.readyState == 4) {
            var a = document.createElement('a');
            a.href = window.URL.createObjectURL(xhr.response);
            a.download = fileName;
            a.click();
        }
    };

    xhr.send();
}

downloadFile 這個函式接收一個參數 _fileUrl 指出檔案路徑
var xhr = new XMLHttpRequest() 建立一個 xhr 物件
withCredentials這個屬性預設為false,
因為 XMLHTTPRequest2 物件才允許CORS(Cross-Origin Resource Sharing),
所以檢查是否有支援withCredentials屬性,
該屬性指示是否使用如cookie或授權標頭檔等憑證進行跨站存取控制(cross-site Access-Control)請求。

而IE 8與IE 9只能使用 XDomainRequest 物件處理 CORS 請求(IE8,9不支援XHR2)
responseType 屬性指定回應狀態,
可以為 blob, json, text 等等,
為了方便後續創造連結,所以指定回應狀態為"blob"
onreadystatechange 這個函式會在 readyState 屬性改變時被呼叫
而 readyState 屬性值為 4 時,表示作業完成。
此時便可以創造一個元素 a,並且呼叫 createObjectURL 方法賦予 href 屬性值,
a.download可以為下載檔案命名,最後呼叫 click 方法完成檔案下載。

還有一件事情須處理,存放檔案的主機要設定允許跨領域存取的權限
後端採用 Node.js 與 Express framework 進行開發
app.configure(function(){ 
  app.use(function(req, res, next) {
      res.header('Access-Control-Allow-Origin', "*");
      res.header('Access-Control-Allow-Credentials', true);
      res.header('Access-Control-Allow-Methods', "GET");
      next();
  });
});

簡單講要幫 response 設定允許跨領域存取的 Header,
'Access-Control-Allow-Origin' 設定允許的請求來源
'Access-Control-Allow-Methods'設定允許的方法,如 GET, POST 等
如果前端 xhr.setRequestHeader 有自行定義 Header 的話
那 Server 這邊也要多加 'Access-Control-Allow-Headers' 權限
res.header('Access-Control-Allow-Headers', 'X-Requested-With');

就允許帶有 header 為 'X-Requested-With' 的請求。
但要注意的是,因為安全性的關係,XDomainRequest不支援客製化 Header
也限制 Method only GET or POST,Protocol only HTTP or HTTPS
還好IE 10開始支援 XMLHTTPRequest2

2013年11月20日 星期三

【jQuery】hide() 與 fadeOut()

jQuery 的兩個動畫函式 hide() 與 fadeOut() 都具有隱藏效果。

需求是當游標滑入指定區域時,浮現該按鈕,點擊按鈕後可使按鈕180度旋轉。

實現旋轉方式是設定 CSS 的 transform 值, rotate( '旋轉度數' deg )。

若使用 hide() 與 show() 來實作隱藏與浮現效果,
元素隱藏之前的旋轉度數會被保留。

但使用 fadeOut() 與 fadeIn() 來實作的話,
旋轉度數的 CSS 效果會消失。

探究其原因,在於 fadeOut 與 fadeIn 會重寫 DOM element 的 style,
導致原本 style 內的 transform 值消失,因此無法保留旋轉度數。

順便紀錄一下觀察到的 hide() 與 fadeOut() 差異,
相同之處:
  1. display值,設為none
  2. opacity值,變更為0

相異之處:
  1. hide() 會將 width 與 height 的值也變更為0,fadeOut() 不改變
  2. hide() 會保留 style 內的 transform 值

2013年11月12日 星期二

【Node.js】Create Http Server

自己以前寫網站習慣,前端使用JavaScript(or jQuery),後端使用PHP,使用Apache建立Server。

而Node.js則打破此框架,簡單講就是,伺服器端的JavaScript! 

為了實現此概念,Node.js借助Google V8引擎在後端運行JavaScript。

想從建立一個基礎Http Server入門,範例code包含三個觀念,使用模組、函數傳遞以及回呼(callback)。
var http = require("http");

function onRequest(request, response) {
  console.log("Request received.");
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}

http.createServer(onRequest).listen(8888);

console.log("Server has started.");
第一行code很簡單,呼叫Node.js內建http模組並存入http變數。

接下來寫一個onRequest函數處理http的請求,這邊我們可以看到http使用createServer方法時,onRequest這個函數被當成是參數來傳遞,此即所謂的函數傳遞。

而Server監聽8888 port同時等待HTTP的請求,當有請求發生時,執行onRequest函式,此即所謂callback。
callback:給甲方法傳遞乙函式,等到對應事件發生時,才執行乙函式。
以上述code來看的話→
甲方法 ─ createServer
乙函式 ─ onRequest
對應事件 ─ HTTP的請求
補充一下,乙函式也很常使用匿名函式。

最後一行code會在命令行上輸出"Server has started.",幫助我們測試程式流程與了解事件的觸發順序,此程式流程為非同步流程,因為http.createServer後,程式會繼續執行,等到有http請求才去執行onRequest函式。

當我們執行腳本後

當我們在瀏覽器輸入localhost:8888後

最後回到命令行會看到
當我們使用瀏覽器讀取網頁時,我們的伺服器有可能會輸出兩次"Request received."。原因為何?我們可以修改code增加解析路徑的功能。

修改code如下
var http = require("http"),
    url = require("url");

function start() {
    function onRequest(request, response) {
        var pathname = url.parse(request.url).pathname;
        console.log("Request for " + pathname + " received.");
        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("Hello Node.js");
        response.end();
    }
    
    http.createServer(onRequest).listen(8888);
    console.log("Server has started.");
}

exports.start = start;

使用Node.js內建url模組,並呼叫其parse方法幫我們解析request.url,
即分析HTTP的請求路徑為何。

腳本編譯完成後,我們一樣開啟browser輸入localhost:8888
然後回到命令列的地方觀看log訊息

觀看log訊息可以知道請求路徑。由此得知,當我們在存取http://localhost:8888的當下, 伺服器也嘗試存取 http://localhost:8888/favicon.ico 。 因此我們上一段code,log訊息才會出現兩次"Request received."。