Node.js的誕生
Nodejs的創(chuàng)始人Rayn Dahl發(fā)現(xiàn)PHP這種腳本語(yǔ)言,在處理網(wǎng)頁(yè)請(qǐng)求的時(shí)候,隨著訪問(wèn)量上來(lái)物遇,要讓W(xué)eb業(yè)務(wù)支持更多的用戶俩功,就需要增加服務(wù)器的配置或者增加搭建集群,則這個(gè)時(shí)候的成本就上升了扔傅。
Rayn Dahl這個(gè)時(shí)候?qū)hrome瀏覽器的V8引擎(目前世界上最快的JS解析引擎)移植到了服務(wù)器上耍共,開(kāi)發(fā)出了Node.js平臺(tái)。
2009年底猎塞,Ryan Dahl在柏林舉行的JSConf EU會(huì)議上發(fā)表關(guān)于Node.js的演講试读,之后Node.js逐漸流行于世。
Node.js是一個(gè)平臺(tái)不是一個(gè)語(yǔ)言荠耽,開(kāi)發(fā)語(yǔ)言仍然是JavaScript钩骇。此時(shí)Node.js平臺(tái)可以讓我們用JavaScript語(yǔ)言來(lái)開(kāi)發(fā)服務(wù)器程序。
Node.js的安裝
node.js可以安裝在windows铝量、mac伊履、linux上,只需要下載對(duì)應(yīng)平臺(tái)的軟件即可款违。
nodejs官網(wǎng):http://nodejs.org/
nodejs中文網(wǎng):http://nodejs.cn/
本次使用 8.7.0 這個(gè)版本進(jìn)行演示唐瀑。
下載對(duì)應(yīng)的版本后,全程下一步進(jìn)行安裝即可插爹。
Node.js的入門(mén)使用
javascript需要宿主環(huán)境才能運(yùn)行哄辣。一般來(lái)說(shuō)我們的瀏覽器可以提供該環(huán)境请梢;但是nodejs平臺(tái)也可以提供該環(huán)境。
在nodejs平臺(tái)中運(yùn)行js文件力穗,此時(shí)需要使用CMD窗口毅弧。此時(shí)需要將CMD的“光標(biāo)路徑”更改為我們的項(xiàng)目文件夾。在對(duì)應(yīng)的文件里面編寫(xiě)代碼当窗,然后使用node運(yùn)行即可够坐。
> node demo1.js
由于nodejs平臺(tái)沒(méi)有DOM所以不能使用下面的語(yǔ)法:
window、document崖面、alert元咙、document.getElementById()……
但是nodejs能夠識(shí)別函數(shù)、if語(yǔ)句巫员、for庶香、while等等js核心語(yǔ)法。
nodejs常見(jiàn)模塊
http模塊
nodejs中的內(nèi)置模塊http模塊简识,可以提供web服務(wù)赶掖。
// 得到內(nèi)置http模塊
var http = require("http");
//創(chuàng)建服務(wù)器,使用createServer方法來(lái)創(chuàng)建服務(wù)器七扰。
//回調(diào)函數(shù)中有一個(gè)req參數(shù)表示請(qǐng)求奢赂,res參數(shù)表示響應(yīng)。
var server = http.createServer(function(req,res){
res.setHeader("Content-Type","text/html;charset=UTF8");
//輸出
res.write("哈哈");
res.end("Hello World!!!");
});
// 監(jiān)聽(tīng)3000端口
server.listen(3000);
fs模塊
fs是nodejs提供的一個(gè)用于讀取磁盤(pán)文件的模塊
fs模塊最重要的api就是readFile颈走,可以異步讀取文件膳灶,第一個(gè)參數(shù)就是要讀取的文件路徑(注意:必須以./開(kāi)頭,表示從當(dāng)前js文件出發(fā)尋找文件)疫鹊。第二個(gè)參數(shù)是回調(diào)函數(shù)袖瞻,表示讀取完畢之后做的事情司致。
var fs = require('fs');
fs.readFile("./data.txt" , function(err , data){
console.log(data);
});
Express框架
問(wèn)題引入
做http服務(wù)的時(shí)候拆吆,不方便:
- 匹配URL很不方便
- 使用靜態(tài)頁(yè)面不方便 fs.readFile(function(err,data){res.end(data)})
- 不能靜態(tài)化一個(gè)文件夾,我們想將一個(gè)文件夾中的所有文件自動(dòng)擁有路由脂矫,實(shí)現(xiàn)不了
Express簡(jiǎn)化了HTTP應(yīng)用程序的開(kāi)發(fā)枣耀。
cnpm intsall --save express
創(chuàng)建app和app的監(jiān)聽(tīng)
我們引入express之后,這個(gè)express是一個(gè)函數(shù)庭再,這個(gè)函數(shù)可以調(diào)用創(chuàng)建出一個(gè)app對(duì)象捞奕。
今后所有的操作都是用app對(duì)象來(lái)完成,需要注意的是拄轻,一個(gè)程序中只有一個(gè)app颅围。
也就是說(shuō)express不能多次調(diào)用。
var express = require("express");
var app = express();
// 業(yè)務(wù)代碼
app.listen(3000);
中間件
app.動(dòng)詞("地址" , function(req,res){
});
// 示例
var express = require("express");
var app = express();
app.get("/get" , function(req,res){
console.log("get");
});
app.post("/post" , function(req,res){
console.log("post");
});
app.listen(3000);
中間件通配符-get參數(shù)
用:來(lái)表示表示一個(gè)通配恨搓,在程序中可以通過(guò)req.params.***得到它院促。
app.get("/:uid/:typeid" , function(req,res){
var uid = req.params.uid;
var typeid = req.params.typeid;
res.send(uid + typeid);
});
用next()放行攔截
當(dāng)一個(gè)中間件已經(jīng)匹配了路徑筏养,但是自己不希望單獨(dú)處理這次請(qǐng)求,可以用next來(lái)放行常拓。
輸出
輸出可以用res.send()做輸出渐溶,會(huì)自動(dòng)加上utf-8。
- res.send("中文");
- res.json({"username":"andy"});
- res.jsonp({"username":"andy"}); // 如果輸出的內(nèi)容是一個(gè)JSONP弄抬,此時(shí)要用res.jsonp()來(lái)輸出茎辐,此時(shí)它會(huì)自動(dòng)檢測(cè)callback的GET請(qǐng)求,并且加上圓括號(hào)的調(diào)用掂恕。
- res.sendFile(__dirname + "/public/index.html");//如果輸出的是一個(gè)外置頁(yè)面拖陆,此時(shí)要用sendFile()這個(gè)API,注意這里必須要用絕對(duì)路徑竹海,此時(shí)我們用__dirname來(lái)進(jìn)行一個(gè)拼合慕蔚。
- res.redirect("http://www.163.com");//如果想要跳轉(zhuǎn)頁(yè)面,用res.redirect()即可
靜態(tài)化一個(gè)文件夾
如果我們想讓某文件夾中的所有文件自動(dòng)擁有路由斋配,此時(shí)非常簡(jiǎn)單孔飒,一句話即可。
app.use( express.static("public") );
//更進(jìn)一步艰争,如果我們不希望靜態(tài)的文件夾出現(xiàn)在底層坏瞄,而是在URL中體現(xiàn)public的名字。
app.use("/public" , express.static("public"));
Express中的GET請(qǐng)求和POST請(qǐng)求參數(shù)
GET請(qǐng)求參數(shù)的獲得
GET請(qǐng)求參數(shù)的識(shí)別實(shí)際上就是URL地址的解析甩卓。URL解析使用內(nèi)置的url模塊的parse方法即可鸠匀。
var url = require("url");
app.get("/users" , function(req,res){
var query = url.parse(req.url , true).query;
console.log("服務(wù)器收到了前端交來(lái)的數(shù)據(jù)" , query);
});
POST請(qǐng)求參數(shù)的獲得
POST請(qǐng)求的參數(shù)攜帶在上行報(bào)文的報(bào)文體中。
我們使用npm包formidable來(lái)識(shí)別這樣的上行報(bào)文逾柿。
API:https://www.npmjs.com/package/formidable
cnpm intsall formidable --save
var formidable = require('formidable');
app.post("/posts" , function(req,res){
var form = new formidable.IncomingForm();
form.parse(req , function(err , fields , files){
console.log( fields );
});
});
其他請(qǐng)求
注意只有GET請(qǐng)求是通過(guò)URL綴?參數(shù)來(lái)傳遞參數(shù)的缀棍。其他的http請(qǐng)求,都是通過(guò)上行報(bào)文來(lái)傳參數(shù)的。formidable能夠識(shí)別其他的請(qǐng)求的參數(shù)式矫。
MongoDB
NoSQL簡(jiǎn)介
NoSQL就是除開(kāi)關(guān)系型數(shù)據(jù)庫(kù)的統(tǒng)稱行疏。
MongoDB數(shù)據(jù)庫(kù)的安裝
mongobooster可視化數(shù)據(jù)庫(kù)管理軟件
NodeJS操作MongoDB
手冊(cè):https://docs.mongodb.com/ecosystem/drivers/node-js/
或者:https://www.npmjs.com/package/mongodb
> cnpm install --save mongodb
var MongoClient = require('mongodb').MongoClient;
//數(shù)據(jù)庫(kù)的地址,最末尾的斜杠是數(shù)據(jù)庫(kù)的名稱
var url = 'mongodb://localhost:27017/ceshi';
MongoClient.connect(url, function(err, db) {
if(!err){
console.log("數(shù)據(jù)庫(kù)連接成功");
}else{
console.log("數(shù)據(jù)庫(kù)連接失敗");
return;
}
//查詢
db.collection("collect1").find({}).toArray(function(err , docs){
console.log(docs);
});
//增加
db.collection("collect1").insert({"name":"asion", "age":23},function(err){
if(!err){
console.log("插入成功");
}
});
});
原生nodejs操作mongodb問(wèn)題很多:
- 語(yǔ)法形式上大的回調(diào)函數(shù)太大了青瀑,要包裹所有的代碼,甚至要包裹express的中間件萧诫;
- 不利于MVC編程斥难,因?yàn)檫@些寫(xiě)代碼幾乎不能將所有對(duì)數(shù)據(jù)庫(kù)的操作封裝到一個(gè)文件中。
Mongoose
簡(jiǎn)介
Mongoose簡(jiǎn)化了nodejs對(duì)nodejs的操作帘饶。
安裝
> cnpm install --save mongoose
基本使用
- 創(chuàng)建schema哑诊,根據(jù)schema創(chuàng)建model
var mongoose = require("mongoose");
//創(chuàng)建schema
var studentSchema = new mongoose.Schema({
"id" : Number,
"username" : String,
"age" : Number,
"gender" : String
});
//通過(guò)schema創(chuàng)建model 對(duì)一個(gè)參數(shù)代表是集合的名稱,到時(shí)候會(huì)在mongodb里面轉(zhuǎn)換為小寫(xiě)及刻,并且轉(zhuǎn)換為復(fù)數(shù)形式
var Student = mongoose.model("Student" , studentSchema);
//暴露
module.exports = Student;
- 根據(jù)模型得到實(shí)例化對(duì)象
var mongoose = require('mongoose');
//連接數(shù)據(jù)庫(kù)
mongoose.connect('mongodb://localhost/xsgl');
//連接我們的model
var Student = require("./models/Student.js");
//實(shí)例化一個(gè)Student類的實(shí)例:
var xiaoming = new Student({
"id" : 10001 ,
"age" : 12,
"gender" : "男",
"username" : "小明"
});
//調(diào)用它的save方法即可放到數(shù)據(jù)庫(kù)中持久化
xiaoming.save(function(err){
if(err){
console.log("保存失敗");
}else{
console.log("保存成功");
}
});
curd操作
增加
// 方式一
var xiaoming= new Student({
"id" : 10001 ,
"age" : 12,
"gender" : "男",
"username" : "小明"
});
xiaoming.save((err)=>{
!err && console.log("成功");
});
// 方式二
Student.create({
"id" : 10001 ,
"age" : 12,
"gender" : "男",
"username" : "小明"
},(err)=>{
!err && console.log("成功");
刪
// 方式一:先查詢記錄镀裤,然后remove
Student.find({"username" : "asion"} , function(err , results){
var rs= results[0];
rs.remove((err)=>{
!err && console.log("成功");
});
});
// 方式二:
Student.remove({"username" : "asion"} , (err)=>{
!err && console.log("成功");
});
改
// 方式一
Student.find({"username" : "asion"} , function(err , results){
var thepeople = results[0];
thepeople.sex = "女";
thepeople.save((err)=>{
!err && console.log("成功");
});
});
// 方式二:
Student.update({"username" : "asion"} , {"$set" : {"age" : 99}} , function(err){
!err && console.log("成功");
});
查
Student.find({"username" : "asion"} , function(err , results){
});
模板引擎
簡(jiǎn)介
如果要使用模板引擎穷当,分為如下四步:
- 安裝依賴,npm install --save ejs
- 設(shè)置默認(rèn)模板引擎 app.set("view engine" , "ejs");
- 在views文件夾中創(chuàng)建一個(gè).ejs后綴的頁(yè)面淹禾,就是模板
- 在express的中間件中用res.render()來(lái)呈遞視圖馁菜,語(yǔ)法就是res.render(模板文件名字 , {字典});
安裝模板引擎
> cnpm install --save express ejs
// 視圖代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<div class="wrap">
<h1><%=content%></h1>
</div>
</body>
</html>
// 業(yè)務(wù)代碼
var express = require("express");
var app = express();
//設(shè)置默認(rèn)模板引擎為ejs
app.set("view engine" , "ejs");
app.get("/" , function(req,res){
//現(xiàn)在多了一個(gè)res.render()表示使用模板頁(yè)面
//不需要加上views文件夾,因?yàn)槟0逡婺J(rèn)就是放在views文件夾中的铃岔,也不需要加上.ejs后綴
res.render("detail" , {
"contente" : "網(wǎng)頁(yè)內(nèi)容"
});
});
app.listen(3000);
注意事項(xiàng)
- views文件夾可以改變汪疮,使用語(yǔ)句
app.set("views" , "templates");
// 這樣所有的.ejs文件都要放到 templates文件夾中。
- 拓展名必須是.ejs毁习,render的時(shí)候不需要寫(xiě).ejs
- 可以使用一些for循環(huán)和if語(yǔ)句
<ul>
<% for(var i = 0 ; i < data.length ; i++){ %>
<li><%= data[i] %></li>
<% } %>
</ul>
// <% %>表示for循環(huán)智嚷、if語(yǔ)句;
// <%= %>表示輸出
擴(kuò)展
其他的模板引擎pug(原名叫做Jade):
https://www.npmjs.com/package/pug
cookie和session
簡(jiǎn)介
HTTP是無(wú)連接的纺且,所以產(chǎn)生了身份識(shí)別問(wèn)題
使用
express中使用cookie需要安裝一個(gè)依賴cookie-parser
> cnpm install --save cookie-parser
// 設(shè)置
res.cookie('uid', 1, { maxAge: 86400 });
// 讀取
var cookieParser = require('cookie-parser');
app.use(cookieParser());
//中間件中
app.get("/users" , function(req,res){
req.cookies.uid;
});
session
session在express中的使用盏道,需要npm包:express-session。
> npm install --save express express-session ejs
app.post("/login" , function(req,res){
var form = new formidable.IncomingForm();
form.parse(req , function(err , fields){
// 設(shè)置session數(shù)據(jù)
req.session.login = true;
req.session.username= "andy";
});
});
文件上傳
頭像的上傳很簡(jiǎn)單载碌,因?yàn)閒ormidable天生支持文件的上傳猜嘱,用files來(lái)接收即可。
gm圖片裁剪
http://www.graphicsmagick.org/
> cnpm install --save gm
var gm = require('gm');
gm(avatarurl).crop(w,h,x,y).write(avatarurl, function (err) {
console.log("裁剪成功嫁艇!");
});