Spring 2019 。 Ric Huang
還記得這幾次的上課與作業我們都是使用 "create-react-app" 這個工具,自動產生整個 React App 的架構,然後利用 "npm start" 來執行 app.
但你有沒有好奇過為什麼我們執行 app 是去打開 "localhost:3000", 而不是用 browser 打開 "index.html"?
你有沒有發現只要你更新任何程式碼,都會自動 trigger "localhost:3000" 的更新?
Basically, 當你執行 "npm start" 之後,你就啟動了一個 "node.js server", 跑在你的電腦 (i.e. localhost) 上,並且透過 port 3000 來跟外界溝通。
而伺服器(server)上面的後端服務(backend service)會一直傾聽相關的需求,例如:發現程式碼有更新,就啟動重新編譯的動作,並刷新服務程式
一個完整的網路服務應用通常要有一個後台(backend),並且有資料庫(database)來儲存用戶或者是服務流程中的相關資料
而上述的服務通常會放在一個有固定 IP 的伺服器,並且去申請 domain name, 讓客戶端(client)可以透過 URL(e.g. 網址) 來取得服務
基本上任何可以跑在伺服器(電腦)的程式語言都可以用來實現後端的 server
由 Ryan Dahl 在 2009 開發,目標在實現 "JavaScript Everywhere" 的典範,讓 web development 可以統一在一個語言底下
基本上 Node.js 就是一個 JavaScript 的 runtime environment, 讓 JavaScript 可以在 Browser 以外的環境執行,所以 Node.js 可以用來開發以 JS 為基礎的後端程式
Node.js 雖然有 .js, 但它並不是指某個單一的 JS 檔案
每六個月有個 Major Release (四月、十月)
奇數版本在十月份發行的時候,先前在四月發行的偶數版本就會自動變成 Long Term Support (LTS) 版本, 然後會被積極、持續地維護 18 個月,結束後會被延長維護 12 個月,然後就壽終正寢
奇數版本沒有 LTS
let { stat, exists, readFile } = require('fs');
const math = require('math');
console.log(math.add(1, 2));
exports.incrementOne = function (num) {
return math.add(num, 1);
};
export var firstName = 'Michael';
export function multiply(x, y) { return x * y; } as MM;
export class MyClass extends React.Component...;
import { foo } from './myApp.js';
import { aVeryLongName as someName } from '../someFile.js'
// Add.js
export default (a, b) => (a+b);
// import an (anonymous) function from "Add.js"
// The name of the function is (re-)named to "MyAdd"
import MyAdd from "Add";
[Example] Save the following as a file "test.js"
const http = require('http');
const PORT = process.env.PORT || 3000;
const server = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World!');
});
server.listen(PORT, function() {
console.log(`Server listening on: http://localhost:${PORT}`);
});
當然,你也可以直接用 node 的 command line.
只要在 terminal 鍵入 "node", 你就可以試用各種 Node.js 的指令與模組了! (Use .help to get help)
var app = require('../app');
var http = require('http');
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
var express = require('express');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(...); // middlewares
module.exports = app; // for ./bin/www
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
extends layout
block content
h1= title
p Welcome to #{title}
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
POST /users/123 HTTP/1.1 // Request-line
Host: www.example.com // header fields
Accept-Language: en-us // ..
Connection: Keep-Alive // ..
// empty line
licenseID=string&content=string&/paramsXML=string // message-body
假設現在我們要點餐,
我們必須先知道菜單是甚麼(get),
我們會向服務生點餐(post),
我們想要取消剛才點的餐點(delete),
我們想要重新點一次(put),
我們想要加點甜點和飲料(patch)。
HTTP/1.1 200 OK // Status-line
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Connection: keep-alive
Content-Length: 53
Content-Type: text/html; charset=UTF-8
Date: Tue, 11 Oct 2016 16:32:33 GMT
ETag: "53-1476203499000"
Last-Modified: Tue, 11 Oct 2016 16:31:39 GMT
// empty line
<html> // message-body
<body>
<h1>Hello, World!</h1>
</body>
</html>
Express is a routing and middleware web framework that has minimal functionality of its own: An Express application is essentially a series of middleware function calls.
Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.
var express = require('express');
var app = express();
app.use([path,] callback [, callback...]);
app.METHOD(path, callback [, callback ...]);
// METHOD can be:
// checkout copy delete get head lock
// merge mkactivity mkcol move m-search
// notify options patch post purge put
// report search subscribe trace unlock
// unsubscribe
var app = express()
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
})
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
app.use('/user/:id', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id)
next()
}, function (req, res, next) {
res.send('User Info')
})
// This will never be called!
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id)
})
function logOriginalUrl (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}
function logMethod(req, res, next) {
console.log('Request Type:', req.method)
next()
}
var logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, function (req, res, next) {
res.send('User Info')
})