Fork me on GitHub

爬虫溢关于express

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)
-------------本文结束感谢您的阅读-------------