Express框架:
在说express框架之前我们先简单介绍一下淘宝cnpm镜像:
淘宝做了一个npm的镜像,叫做cnpm。
官网: npm.taobao.org
特别简单复制下面的程序到CMD中按回车就行了:
npm install -g cnpm --registry=https://registry.npm.taobao.org
-g安装表示安装命令行程序,安装完毕之后,我们就能在CMD中使用cnpm了。
整体感知
做http服务的时候,不方便:
- 匹配URL很不方便 if(//.test()){}
- 使用静态页面不方便 fs.readFile(function(err,data){res.end(data)})
- 不能静态化一个文件夹,我们想将一个文件夹中的所有文件自动拥有路由,实现不了
- ……
Express简化了HTTP应用程序的开发。
安装依赖:
cnpm intsall --save express
express官网:http://www.expressjs.com.cn/
创建app和app的监听
我们引入express之后,这个express是一个函数,这个函数可以调用创建出一个app对象。
今后所有的操作都是用app对象来完成,需要注意的是,一个程序中只有一个app。
也就是说express不能多次调用。
express程序的基本结构:
var express = require("express");
var app = express();
中间件
中间件
中间件
中间件
app.listen(3000);
中间件
动词
中间件的语法:
app.动词("地址" , function(req,res){
});
我们先说动词,它是26种HTTP请求,必须是小写字母:
动词表示当用户用这种请求访问这个页面的时候做的事情。
我们现在就可以区分出用GET请求访问首页和POST请求访问首页做不同的事情:
var express = require("express");
var app = express();
app.get("/" , function(req,res){
console.log("A");
});
app.post("/" , function(req,res){
console.log("B");
});
app.listen(3000);
中间件的路径是自动比对主干部分
路径已经自动被url.parse()
了,也就是说express会用用户输入的URL的主干部分来进行比对。
也就是说我的中间件如果是:
app.get("/xinwen" , function(req,res){
res.send("<h1>新闻频道</h1>");
});
下面的URL都是合法的能够进入这个频道的:
http://127.0.0.1:3000/xinwen
http://127.0.0.1:3000/xinwen/
http://127.0.0.1:3000/xinwen?id=234234
http://127.0.0.1:3000/xinwen?id=234234#234234345435234
中间件可以有通配符
用:
来表示画一个通配,要注意这里没有正则表达式的,在程序中可以通过req.params.***
得到它。
app.get("/:banji/:xuehao" , function(req,res){
var banji = req.params.banji;
var xuehao = req.params.xuehao;
res.send(banji + "班" + xuehao + "号");
});
今后的编程就不用写match()和test()方法了。
还有一种*的通配符,不常用,自己看手册。
中间件的顺序很关键
比如我们输入班级、学号查询学生信息,但是不能查询3班8号。此时一定要注意中间件的顺序。
中间件一旦匹配上的路由,此时不再进行其他匹配。有一种“拦截”的感觉。
app.get("/3/8" , function(req,res){
res.send("<h1>校长的儿子你也敢查!</h1>")
});
app.get("/:banji/:xuehao" , function(req,res){
var banji = req.params.banji;
var xuehao = req.params.xuehao;
res.send(banji + "班" + xuehao + "号");
});
用next()放行拦截
当一个中间件已经匹配了路径,但是自己不希望单独处理这次请求,可以用next来放行。
我们做一个业务能够查询学生或者老师的信息,不管查询什么都要增加计数器的数量。此时可以单独用一个中间件写计数器,放行请求即可:
app.get("/chaxun/*" , function(req,res,next){
count++;
next();
});
app.get("/chaxun/xuesheng/:banji/:xuehao" , function(req,res){
res.send("查询" + req.params.banji + "班" + req.params.xuehao + "号" + "<br /> 共查询了" + count + "次");
});
app.get("/chaxun/laoshi/:gonghao" , function(req,res){
res.send("查询" + req.params.gonghao + "工号的老师" + "<br /> 共查询了" + count + "次");
});
输出
输出可以用res.send()做输出,会自动加上utf-8。
app.get("/" , function(req,res){ res.send("中文"); });
如果输出的内容是一个JSON,此时要用res.json()来进行输出。
app.get("/" , function(req,res){ res.json({"a":1,"b":2,"c":[1,2,3,4,{"m":4}]}); });
如果输出的内容是一个JSONP,此时要用res.jsonp()来输出,此时它会自动检测callback的GET请求,并且加上圆括号的调用。
app.get("/" , function(req,res){ res.jsonp({"a":1,"b":2,"c":[1,2,3,4,{"m":4}]}); });
复习一下jQuery中的jsonp跨域:
$.ajax({ "url" : "/?callback=?", "dataType" : "JSONP", "success" : function(data){ } }); //机理 jQuery帮我们创建了一个<script>标签,src是这个url,用随机的字符串替换了? 用随机的字符串为名字创建了一个全局的函数,将success指向它。
如果输出的是一个外置页面,此时要用sendFile()这个API,注意这里必须要用绝对路径,此时我们用__dirname来进行一个拼合。
app.get("/",function(req,res){ //_dirname表示当前文件所在的目录 res.sendFile(_dirname+"/public/a.html"); });
如果想要跳转页面,用res.redirect()即可
app.get("/",function(req,res){ res.redirect("http://www.163.com"); });
复习:
res.send(); res.sendFile(); res.json(); res.jsonp(); res.redirect();
静态化一个文件夹
如果我们想让某文件夹中的所有文件自动拥有路由,此时非常简单,一句话即可(最好记下来):app.use(express.static("public"));
此时将把public文件进行静态化。
我们在app.js
中静态化public文件夹:
var express = require("express");
var app = express();
app.use(express.static("public"));
app.listen(3000);
此时:
更进一步,如果我们不希望静态的文件夹出现在底层,而是在URL中体现public的名字,此时:
app.use("/public",express.static("public"));
Express中的GET请求和POST请求参数的获得
GET请求参数的获得
GET请求参数的识别实际上就是URL地址的解析。URL解析使用内置的url模块的parse方法即可。
var url = require("url");
app.get("/tijiao" , 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 install formidable --save
后台app.js
识别POST请求需要使用formidable这个包。
var formidable = require('formidable');
app.post("/tijiao" , function(req,res){
var form = new formidable.IncomingForm();
form.parse(req , function(err , fields , files){
res.json({"result" : 1})
});
});
总结一下两种请求后台怎么得到参数(伪代码):
GET请求 | POST请求 |
---|---|
var url = require(“url”); var query = url.parse(req.url , true).query; | var formidable = require(“formidable”); app.post(“/tijiao” , function(req,res){ var form = new formidable.IncomingForm(); form.parse(req , function(err , fields , files){ console.log(fields); }); }); |
其他请求
一共有26种请求,注意只有GET请求是通过URL缀?参数来传递参数的。其他的25种请求,都是通过上行报文来传参数的。formidable能够识别其他25种请求的参数。
先说一下jQuery如何发出DELETE请求:
$("#btn3").click(function(){
$.ajax({
"url" : "/tijiao" ,
"type" : "DELETE" ,
"data" : {
"id" : 10086
},
"success" : function(data){
alert(data.result);
}
});
});
我们的Express这样识别它:(你会发现和POST请求的处理方法是一样的,都是formidable):
//识别DELETE请求
app.delete("/tijiao" , function(req,res){
var form = new formidable.IncomingForm();
form.parse(req , (err , fields , files) => {
console.log("服务器收到DELETE请求参数" , fields);
res.json({"result" : 1});
});
});
总结一下:
GET请求 | 其他请求 |
---|---|
var url = require(“url”); var query = url.parse(req.url , true).query; | var formidable = require(“formidable”); app.动词(“/tijiao” , function(req,res){ var form = new formidable.IncomingForm(); form.parse(req , function(err , fields , files){ console.log(fields); }); }); |
RESTful风格路由
注意这个单词的写法:RESTful。REST是Representational State Transfer
。
RESTful风格的路由很简单,指的是用URL表示操作的资源,用HTTP动词表示何种操作。
RESTful风格的路由
事儿 | 处理这个事儿的URL |
---|---|
增加一个学生 | http://127.0.0.1/student (POST) |
删除一个学号为10086的学生 | http://127.0.0.1/student/10086 (DELETE) |
修改一个学号为10086的学生的性别 | http://127.0.0.1/student/10086 (PATCH) |
列出所有学生 | http://127.0.0.1/student (GET) |