玩转nodejs

Node.js的诞生

Nodejs的创始人Rayn Dahl

Nodejs的创始人Rayn Dahl发现PHP这种脚本语言,在处理网页请求的时候,随着访问量上来,要让Web业务支持更多的用户,就需要增加服务器的配置或者增加搭建集群,则这个时候的成本就上升了。

Rayn Dahl这个时候将Chrome浏览器的V8引擎(目前世界上最快的JS解析引擎)移植到了服务器上,开发出了Node.js平台。

2009年底,Ryan Dahl在柏林举行的JSConf EU会议上发表关于Node.js的演讲,之后Node.js逐渐流行于世。

Node.js是一个平台不是一个语言,开发语言仍然是JavaScript。此时Node.js平台可以让我们用JavaScript语言来开发服务器程序。

Node.js的安装

node.js可以安装在windows、mac、linux上,只需要下载对应平台的软件即可。

nodejs官网:http://nodejs.org/

nodejs中文网:http://nodejs.cn/

本次使用 8.7.0 这个版本进行演示。
下载对应的版本后,全程下一步进行安装即可。

Node.js的入门使用

javascript需要宿主环境才能运行。一般来说我们的浏览器可以提供该环境;但是nodejs平台也可以提供该环境。

在nodejs平台中运行js文件,此时需要使用CMD窗口。此时需要将CMD的“光标路径”更改为我们的项目文件夹。在对应的文件里面编写代码,然后使用node运行即可。


> node demo1.js

由于nodejs平台没有DOM所以不能使用下面的语法:
window、document、alert、document.getElementById()……

但是nodejs能够识别函数、if语句、for、while等等js核心语法。

nodejs常见模块

http模块

nodejs中的内置模块http模块,可以提供web服务。


// 得到内置http模块
var http = require("http");

//创建服务器,使用createServer方法来创建服务器。
//回调函数中有一个req参数表示请求,res参数表示响应。
var server = http.createServer(function(req,res){
      res.setHeader("Content-Type","text/html;charset=UTF8");
    //输出
      res.write("哈哈");
      res.end("Hello World!!!");
});

// 监听3000端口
server.listen(3000);

fs模块

fs是nodejs提供的一个用于读取磁盘文件的模块

fs模块最重要的api就是readFile,可以异步读取文件,第一个参数就是要读取的文件路径(注意:必须以./开头,表示从当前js文件出发寻找文件)。第二个参数是回调函数,表示读取完毕之后做的事情。


var fs = require('fs');

fs.readFile("./data.txt" , function(err , data){
    console.log(data);
});

Express框架

问题引入

做http服务的时候,不方便:

  1. 匹配URL很不方便
  2. 使用静态页面不方便 fs.readFile(function(err,data){res.end(data)})
  3. 不能静态化一个文件夹,我们想将一个文件夹中的所有文件自动拥有路由,实现不了

Express简化了HTTP应用程序的开发。

cnpm intsall --save express

创建app和app的监听

我们引入express之后,这个express是一个函数,这个函数可以调用创建出一个app对象。
今后所有的操作都是用app对象来完成,需要注意的是,一个程序中只有一个app。
也就是说express不能多次调用。

var express = require("express");
var app = express();
//  业务代码

app.listen(3000);

中间件

app.动词("地址" , 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参数

用:来表示表示一个通配,在程序中可以通过req.params.***得到它。


app.get("/:uid/:typeid" , function(req,res){
    var uid = req.params.uid;
    var typeid = req.params.typeid;

    res.send(uid + typeid);
});

用next()放行拦截

当一个中间件已经匹配了路径,但是自己不希望单独处理这次请求,可以用next来放行。

输出

输出可以用res.send()做输出,会自动加上utf-8。

  1. res.send("中文");
  2. res.json({"username":"andy"});
  3. res.jsonp({"username":"andy"}); // 如果输出的内容是一个JSONP,此时要用res.jsonp()来输出,此时它会自动检测callback的GET请求,并且加上圆括号的调用。
  4. res.sendFile(__dirname + "/public/index.html");//如果输出的是一个外置页面,此时要用sendFile()这个API,注意这里必须要用绝对路径,此时我们用__dirname来进行一个拼合。
  5. res.redirect("http://www.163.com");//如果想要跳转页面,用res.redirect()即可

静态化一个文件夹

如果我们想让某文件夹中的所有文件自动拥有路由,此时非常简单,一句话即可。


app.use( express.static("public") );
//更进一步,如果我们不希望静态的文件夹出现在底层,而是在URL中体现public的名字。

app.use("/public" , express.static("public"));

Express中的GET请求和POST请求参数

GET请求参数的获得

GET请求参数的识别实际上就是URL地址的解析。URL解析使用内置的url模块的parse方法即可。

var url = require("url");
app.get("/users" , function(req,res){
    var query = url.parse(req.url , true).query;
    console.log("服务器收到了前端交来的数据" , query);
});

POST请求参数的获得

POST请求的参数携带在上行报文的报文体中。
我们使用npm包formidable来识别这样的上行报文。

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 );
    });
});


其他请求

注意只有GET请求是通过URL缀?参数来传递参数的。其他的http请求,都是通过上行报文来传参数的。formidable能够识别其他的请求的参数。

MongoDB

NoSQL简介

NoSQL就是除开关系型数据库的统称。

MongoDB数据库的安装

https://www.mongodb.com/

mongobooster可视化数据库管理软件

NodeJS操作MongoDB

手册:https://docs.mongodb.com/ecosystem/drivers/node-js/
或者:https://www.npmjs.com/package/mongodb

> cnpm install --save mongodb

var MongoClient = require('mongodb').MongoClient;

//数据库的地址,最末尾的斜杠是数据库的名称
var url = 'mongodb://localhost:27017/ceshi';

MongoClient.connect(url, function(err, db) {
    if(!err){
        console.log("数据库连接成功");
    }else{
        console.log("数据库连接失败");
        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问题很多:

  1. 语法形式上大的回调函数太大了,要包裹所有的代码,甚至要包裹express的中间件;
  2. 不利于MVC编程,因为这些写代码几乎不能将所有对数据库的操作封装到一个文件中。

Mongoose

简介

Mongoose简化了nodejs对nodejs的操作。

安装

> cnpm install --save mongoose

基本使用

  1. 创建schema,根据schema创建model
var mongoose = require("mongoose");

//创建schema
var studentSchema = new mongoose.Schema({
    "id"    : Number, 
    "username"  : String,
    "age"       : Number,
    "gender"        : String
});

//通过schema创建model 对一个参数代表是集合的名称,到时候会在mongodb里面转换为小写,并且转换为复数形式
var Student = mongoose.model("Student" , studentSchema);

//暴露
module.exports = Student;

  1. 根据模型得到实例化对象

var mongoose = require('mongoose');

//连接数据库
mongoose.connect('mongodb://localhost/xsgl');

//连接我们的model
var Student = require("./models/Student.js");

//实例化一个Student类的实例:
var xiaoming = new Student({
    "id" : 10001 ,
    "age" : 12,
    "gender" : "男",
    "username" : "小明"
});

//调用它的save方法即可放到数据库中持久化
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){

});

模板引擎

简介

如果要使用模板引擎,分为如下四步:

  1. 安装依赖,npm install --save ejs
  2. 设置默认模板引擎 app.set("view engine" , "ejs");
  3. 在views文件夹中创建一个.ejs后缀的页面,就是模板
  4. 在express的中间件中用res.render()来呈递视图,语法就是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>

// 业务代码

var express = require("express");
var app = express();

//设置默认模板引擎为ejs
app.set("view engine" , "ejs");

app.get("/" , function(req,res){
    //现在多了一个res.render()表示使用模板页面
    //不需要加上views文件夹,因为模板引擎默认就是放在views文件夹中的,也不需要加上.ejs后缀
    res.render("detail" , {
        "contente" : "网页内容"
    });
});

app.listen(3000);



注意事项

  1. views文件夹可以改变,使用语句
app.set("views" , "templates");
// 这样所有的.ejs文件都要放到 templates文件夹中。
  1. 拓展名必须是.ejs,render的时候不需要写.ejs
  2. 可以使用一些for循环和if语句
<ul>
    <% for(var i = 0 ; i < data.length ; i++){ %>
        <li><%= data[i] %></li>
    <% } %>
</ul>

// <% %>表示for循环、if语句;
// <%= %>表示输出

扩展

其他的模板引擎pug(原名叫做Jade):

https://www.npmjs.com/package/pug

cookie和session

简介

HTTP是无连接的,所以产生了身份识别问题

使用

express中使用cookie需要安装一个依赖cookie-parser


> cnpm install --save cookie-parser
// 设置
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){
                // 设置session数据
        req.session.login = true;
        req.session.username= "andy";

    });
});

文件上传

头像的上传很简单,因为formidable天生支持文件的上传,用files来接收即可。

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("裁剪成功!");
});

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351

推荐阅读更多精彩内容