EXpress: 精简的、灵活的Node.js Web程序框架,为构建单页、多页及混合的Web程序提供了一系列健壮的功能特性。
var http = require('http');
http.createServer(function(req,res){
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello world!');
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');
var http = require('http');
http.createServer(function(req,res){ // 规范化 url,去掉查询字符串、可选的反斜杠,并把它变成小写
var path = req.url.replace(/\/?(?:\?.*)?$/, '').toLowerCase();
switch(path) {
case '':
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Homepage');
break;
case '/about':
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('About');
break;
default:
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');
var http = require('http'),
fs = require('fs');
function serveStaticFile(res, path, contentType, responseCode) {
if(!responseCode) responseCode = 200;
fs.readFile(__dirname + path, function(err,data) {
if(err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('500 - Internal Error');
} else {
res.writeHead(responseCode, { 'Content-Type': contentType });
res.end(data);
}
});
}
http.createServer(function(req,res){ // 规范化 url,去掉查询字符串、可选的反斜杠,并把它变成小写
var path = req.url.replace(/\/?(?:\?.*)?$/, '') .toLowerCase();
switch(path) {
case '':
serveStaticFile(res, '/public/home.html', 'text/html');
break;
case '/about':
serveStaticFile(res, '/public/about.html', 'text/html');
break;
case '/img/logo.jpg':
serveStaticFile(res, '/public/img/logo.jpg', 'image/jpeg');
break;
default:
serveStaticFile(res, '/public/404.html', 'text/html', 404);
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');
npm init
生成一个package.json文件npm install --save express
安装express框架忽略无需添加到代码库的内容
# ignore packages installed by npm
node_modules
# put any other files you don't want to check in here,
# such as .DS_Store (OSX), *.bak, etc.
可以使用index.js,也可以使用与项目相关的[有意义名称].js。
var express = require('express'); // 引入express框架
var app = express();
app.set('port', process.env.PORT || 3000); // 设置执行端口
// 定制 404 页面
app.use(function(req, res){
res.type('text/plain');
res.status(404);
res.send('404 - Not Found');
});
// 定制 500 页面
app.use(function(err, req, res, next){
console.error(err.stack);
res.type('text/plain');
res.status(500);
res.send('500 - Server Error');
});
// 监听端口,执行内容
app.listen(app.get('port'), function(){
console.log( 'Express started on http://localhost:' + app.get('port') + '; press Ctrl-C to terminate.' );
});
app.get('/', function(req, res){
res.type('text/plain');
res.send('Meadowlark Travel');
});
app.get('/about', function(req, res){
res.type('text/plain');
res.send('About Meadowlark Travel');
});
Node | Express |
---|---|
res.end | res.send |
res.writeHead | res.set、res.status、res.type |
Tip:
我们对定制的404页面和500页面的处理与对普通页面的处理有所区别,普通页面路由使用的是app.get()
,而404和500页面使用的是app.use()
。app.use()是Express添加中间件的一种方法,可以看做处理所有没有匹配路由路径的处理器。在Express中,路由和中间件的添加顺序至关重要。如果将404处理器放在所有路由的上面,则所有路由都不能访问了,访问得到的URL都是404.通配符匹配也要放在下面的位置,避免影响了其他子路由等。例如/about*就要放在/about/contact等下面。
模板框架Handlebars,不会对HTML进行抽象,编写的是带特殊标签的HTML,Handlebars 可 以借此插入内容。
npm install --save express3-handlebars
安装视图模板框架 var app = express(); // 设置 handlebars 视图引擎
var handlebars = require('express3-handlebars')
.create({ defaultLayout:'main' });
app.engine('handlebars', handlebars.engine);
app.set('view engine', 'handlebars');
这段代码创建了一个视图引擎,并对 Express 进行了配置,将其作为默认的视图引擎。接 下来创建 views 目录,在其中创建一个子目录 layouts。如果你是一位经验丰富的 Web 开发 人员,可能已经熟悉布局的概念了(有时也被称为“母版页”)。在开发网站时,每个页面 上肯定有一定数量的 HTML 是相同的,或者非常相近。在每个页面上重复写这些代码不仅 非常繁琐,还会导致潜在的维护困境:如果你想在每个页面上做一些修改,那就要修改所 有文件。布局可以解决这个问题,它为网站上的所有页面提供了一个通用的框架。
{{!-- 给网站创建模板 --}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/css/main.css">
</head>
<body>
<header>
<img class="logo" src="/img/moon.jpg" alt="图片加载失败">
</header>
{{{body}}}
</body>
</html>
入口js文件中.create({ 'defaultLayout': 'main' });意味着除非你特别指明,否则视图都用这个布局。之后不同页面的代码都会插入到body处。
在layouts同级,可以创建自定义的home页面、about页面、404页面、500页面等
home.handlebars
<h1>Welcome to Meadowlark Travel</h1>
因为html相关内容在main.handlebars布局页面都已经存在了,所以我们需要要写body处想要的内容即可。同时,可以修改一下访问home的路由,从直接send内容改为引入某个具体的文件
// get 方法配置路由
app.get('/', function(req, res) {
// res.type('text/plain')
// res.send('Home Page')
res.render('home')
})
// 定制500页面
app.use(function(err, req, res, next) {
// console.log(err.stack)
// res.type('text/plain')
// res.status(500)
// res.send('500 - Server Error')
console.log(err.stack)
res.status(500)
res.render(500)
})
此时,我们普通页面已经不需要返回状态码和指定内容了,视图引擎默认会返回 text/html 的内容类型和 200 的状态码。在 catch-all 处理器(提供定制的 404 页面)以及 500 处理器中, 我们必须明确设定状态码。
不使用模板的配置:
app.get('/nolay', function(req, res) {
res.render('nolay', {layout: null})
})
Express 靠中间件处理静态文件和视图。static 中间件可以将一个或多个目录指派为包含静态资源的目录,其中的资源不经过任何 特殊处理直接发送到客户端。你可以在其中放图片、CSS 文件、客户端 JavaScript 文件之 类的资源。
存放静态文件,我们可以在根目录中创建public文件夹,文件夹内放置一张我们需要的图片信息。
在入口文件.js中修改
// 静态资源目录,应该放在所有路由之前,内部所有文件对外开放
app.use(express.static(__dirname + '/public'));
static 中间件相当于给你想要发送的所有静态文件创建了一个路由,渲染文件并发送给客 户端。接下来我们在 public 下面创建一个子目录 img,并把 logo.png 文件放在其中。 现在我们可以直接指向 /img/logo.png(注意:路径中没有 public,这个目录对客户端来说是 隐形的),static 中间件会返回这个文件,并正确设定内容类型。接下来我们修改一下布 局文件,以便让我们的 logo 出现在所有页面上
main.handlebars中引入图片
<img class="logo" src="/img/moon.jpg" alt="图片加载失败">
视图并不只是一种传递静态 HTML 的复杂方式(尽管它们当然能做到)。视图真正的强大 之处在于它可以包含动态信息。
我们可以创建一个用来保存模块的目录。名称任意,但一般被称为lib(library的缩写),与public、views同级,可以在该目录下创建一个fortune.js文件
lib/fortune.js
// 动态数据
var fortuneCookies = [
"Conquer your fears or they will conquer you.",
"Rivers need springs.",
"Do not fear what you don nott know.",
"You will have a pleasant surprise.",
"Whenever possible, keep it simple."
]
// 处理动态数据的方法,随机返回某个数据
exports.getFortune = function() {
const idx = Math.floor(Math.random() * fortuneCookies.length);
return fortuneCookies[idx]
}
上述的数据我们想要在about页面中进行使用,
var fortunes = require('./lib/fortune.js')
app.get('/about', function(req, res) {
// res.type('text/plain')
// res.send('About Page')
res.render('about', {fortune: fortunes.getFortune()})
})
<h1>About Meadowlark Travel</h1>
<p>Your fortune for the day:</p>
<blockquote>{{fortune}}</blockquote>
上述路由、路由对应页面、布局组件最终形成一个简单的express项目,项目结构如下图
<a id="chapter06">
指定的部分我们在浏览网页时,发送到服务器的并不只是URL。当你访问一个网站时,浏览器会发送很多“隐形”信息。服务器会因此得知优先响应哪种语言的页面,它也会发送“用户代理”信息(浏览器、操作系统和硬件设备)和一些其他信息。可以通过以下代码查看请求头信息
app.get('/headers', function(req,res){
res.set('Content-Type','text/plain');
var s = '';
for(var name in req.headers) s += name + ': ' + req.headers[name] + '\n';
res.send(s);
});
app.disable('x-powered-by');
内容类型报头信息非常重要,没有它客户端很难判断如何渲染接收到的内容。内容类型报头就是一种互联网媒体类型,由一个类型、一个子类型及可选参数组成。
例如, text/html;charset=UTF-8 说明类型是 text,子类型是 html,字符编码是 UTF-8。互联网编号分配机构维护了一个官方的互联网媒体类型清单(http://www.iana.org/assignments/media- types/media-types.xhtml)。我们常见的 content type、Internet media type 和 MIME type 是可 以互换的。MIME(多用途互联网邮件扩展)是互联网媒体类型的前身,它们大部分是相同的。
除请求报头外,请求还有一个主体(就像作为实际内容返回的响应主体一样)。一般 GET 请求没有主体内容,但 POST 请求是有的。POST 请求体最常见的媒体类型是 application/ x-www-form-urlendcoded,是键值对集合的简单编码,用 & 分隔(基本上和查询字符串的 格式一样)。如果 POST 请求需要支持文件上传,则媒体类型是 multipart/form-data,它是 一种更为复杂的格式。最后是 AJAX 请求,它可以使用 application/json。
对于任何一个请求,参数可以来自查询字符串、会话、请求体或指定的路由参数。在 Node 应用中,请求对象的参数方法会重写所有的参数。
请求对象(通常传递到回调方法,这意味着你可以随意命名,通常命名为 req 或 request)的生命周期始于 Node 的一个核心对象 http.IncomingMessage 的实例。
响应对象(通常传递到回调方法,这意味着你可以随意命名它,通常命名为 res、resp 或 response)的生命周期始于 Node 核心对象 http.ServerResponse 的实例。Express 添加了一 些附加功能。
// 必须引入中间件 body-parser
app.post('/process-contact', function(req, res){
console.log('Received contact from ' + req.body.name + ' <' + req.body.email + '>'); // 保存到数据库……
res.redirect(303, '/thank-you');
});
// 必须引入中间件 body-parser
app.post('/process-contact', function(req, res){
console.log('Received contact from ' + req.body.name + ' <' + req.body.email + '>');
try { // 保存到数据库……
return res.xhr ?
res.render({ success: true })
:
res.redirect(303, '/thank-you');
} catch(ex) {
return res.xhr ?
res.json({ error: 'Database error.' })
:
res.redirect(303, '/database-error');
}
});
参考书籍-Node与Express开发
总结用法,希望可以帮助到你,
我是Ably,你无须超越谁,只要超越昨天的自己就好~