• 浅析nodejs的http模块


    我们知道传统的HTPP服务器会由Aphche、Nginx、IIS之类的软件来担任,但是nodejs并不需要,nodejs提供了http模块,自身就可以用来构建服务器,而且http模块是由C++实现的,性能可靠。我们在nodejs中的教程或者书籍中常常会通过一个简易的http服务器来作为开头的学习,就像下面这个例子

    var http=require("http");
    
    http.createServer(function(req,res){
        res.writeHead(200,{
            "content-type":"text/plain"
        });
        res.write("hello nodejs");
        res.end();
    }).listen(3000);
    

    打开浏览器,输入localhost:3000我们就可以看到屏幕上的hello nodejs了,这表明这个最简单的nodejs服务器已经搭建成功了。
    nodejs中的http模块中封装了一个HTPP服务器和一个简易的HTTP客户端,http.Server是一个基于事件的http服务器,http.request则是一个http客户端工具,用于向http服务器发起请求。而上面的createServer方法中的参数函数中的两个参数req和res则是分别代表了请求对象和响应对象。其中req是http.IncomingMessage的实例,res是http.ServerResponse的实例,这可以从nodejs中的源码中获取这个信息(当然我们作为初学者,自然是不太可能读懂其源码,推荐慕课网的课程《进击的nodjs基础(一)》,scott老师会带我们基本走一下http模块的源码,会有一个大概的了解)。以下将从http服务器和http客户端简要走一遍http模块

    一、http服务器####


    文章开头使用的createServer方法返回了一个http.Server对象,这其实是一个创建http服务的捷径,如果我们用以下代码来实现的话,也将一样可行

    var http=require("http");
    var server=new http.Server();
    
    server.on("request",function(req,res){
        res.writeHead(200,{
            "content-type":"text/plain"
        });
        res.write("hello nodejs");
        res.end();
    });
    server.listen(3000);
    

    以上代码是通过直接创建一个http.Server对象,然后为其添加request事件监听,其实也就说createServer方法其实本质上也是为http.Server对象添加了一个request事件监听,这似乎更好理解了,那让我们看看http.Server的事件吧

    1、http.Server的事件######

    正如我们上面所说,http.Server是一个基于事件的服务器,她是继承自EventEmitter,事实上,nodejs中大部分模块都继承自EventEmitter,包括fs、net等模块,这也是为什么说nodejs基于事件驱动(关于EventEmitter的更多内容可以在官方api下的events模块找到),http.Server提供的事件如下:

    • request:当客户端请求到来时,该事件被触发,提供两个参数req和res,表示请求和响应信息,是最常用的事件
    • connection:当TCP连接建立时,该事件被触发,提供一个参数socket,是net.Socket的实例
    • close:当服务器关闭时,触发事件(注意不是在用户断开连接时)

    正如上面我们所看到的request事件是最常用的,而参数req和res分别是http.IncomingMessage和http.ServerResponse的实例,那么我们来看看这两个类吧

    2、http.IncomingMessage######

    http.IncomingMessage是HTTP请求的信息,是后端开发者最关注的内容,一般由http.Server的request事件发送,并作为第一个参数传递,http请求一般可以分为两部分:请求头和请求体(更多关于http协议的知识可以查看我之前的笔记http入门与挖坑);其提供了3个事件,如下

    • data:当请求体数据到来时,该事件被触发,该事件提供一个参数chunk,表示接受的数据,如果该事件没有被监听,则请求体会被抛弃,该事件可能会被调用多次(这与nodejs是异步的有关系)
    • end:当请求体数据传输完毕时,该事件会被触发,此后不会再有数据
    • close:用户当前请求结束时,该事件被触发,不同于end,如果用户强制终止了传输,也是用close

    http.IncomingMessage的属性如下:

     
     
    3、http.ServerResponse######

    http.ServerResponse是返回给客户端的信息,决定了用户最终看到的内容,一般也由http.Server的request事件发送,并作为第二个参数传递,它有三个重要的成员函数,用于返回响应头、响应内容以及结束请求

    • res.writeHead(statusCode,[heasers]):向请求的客户端发送响应头,该函数在一个请求中最多调用一次,如果不调用,则会自动生成一个响应头
    • res.write(data,[encoding]):想请求的客户端发送相应内容,data是一个buffer或者字符串,如果data是字符串,则需要制定编码方式,默认为utf-8,在res.end调用之前可以多次调用
    • res.end([data],[encoding]):结束响应,告知客户端所有发送已经结束,当所有要返回的内容发送完毕时,该函数必需被调用一次,两个可选参数与res.write()相同。如果不调用这个函数,客户端将用于处于等待状态。

    看完http服务器,我们看一看http的客户端吧

    二、http客户端####


    http模块提供了两个函数http.request和http.get,功能是作为客户端向http服务器发起请求。

    1、http.request(options,callback)######

    options是一个类似关联数组的对象,表示请求的参数,callback作为回调函数,需要传递一个参数,为http.ClientResponse的实例,http.request返回一个http.ClientRequest的实例。

    options常用的参数有host、port(默认为80)、method(默认为GET)、path(请求的相对于根的路径,默认是“/”,其中querystring应该包含在其中,例如/search?query=byvoid)、headers(请求头内容)

    如下示例代码:

    var http=require("http");
    
    var options={
        hostname:"cn.bing.com",
        port:80
    }
    
    var req=http.request(options,function(res){
        res.setEncoding("utf-8");
        res.on("data",function(chunk){
            console.log(chunk.toString())
        });
        console.log(res.statusCode);
    });
    req.on("error",function(err){
        console.log(err.message);
    });
    req.end();
    

    我们运行这段代码我们在控制台可以发现,必应首页的html代码已经呈现出来了。

    接下来我们来做一个关于POST请求的代码。

    var http=require("http");
    var querystring=require("querystring");
    
    var postData=querystring.stringify({
        "content":"我真的只是测试一下",
        "mid":8837
    });
    
    var options={
        hostname:"www.imooc.com",
        port:80,
        path:"/course/document",
        method:"POST",
        headers:{
            "Accept":"application/json, text/javascript, */*; q=0.01",
            "Accept-Encoding":"gzip, deflate",
            "Accept-Language":"zh-CN,zh;q=0.8",
            "Connection":"keep-alive",
            "Content-Length":postData.length,
            "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
            "Cookie":"imooc_uuid=6cc9e8d5-424a-4861-9f7d-9cbcfbe4c6ae; imooc_isnew_ct=1460873157; loginstate=1; apsid=IzZDJiMGU0OTMyNTE0ZGFhZDAzZDNhZTAyZDg2ZmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjkyOTk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGNmNmFhMmVhMTYwNzRmMjczNjdmZWUyNDg1ZTZkMGM1BwhXVwcIV1c%3DMD; PHPSESSID=thh4bfrl1t7qre9tr56m32tbv0; Hm_lvt_f0cfcccd7b1393990c78efdeebff3968=1467635471,1467653719,1467654690,1467654957; Hm_lpvt_f0cfcccd7b1393990c78efdeebff3968=1467655022; imooc_isnew=2; cvde=577a9e57ce250-34",
            "Host":"www.imooc.com",
            "Origin":"http://www.imooc.com",
            "Referer":"http://www.imooc.com/video/8837",
            "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2763.0 Safari/537.36",
            "X-Requested-With":"XMLHttpRequest",
        }
    }
    
    var req=http.request(options,function(res){
        res.on("data",function(chunk){
            console.log(chunk);
        });
        res.on("end",function(){
            console.log("评论完毕!");
        });
        console.log(res.statusCode);
    });
    
    req.on("error",function(err){
        console.log(err.message);
    })
    req.write(postData);
    req.end();
    

    这段代码我们模拟了向慕课网发起评论的功能,但是因为慕课网对于这种发起方式专门做了重定向,所以我们并不能在评论区看到我们的评论(另外在一些对这种请求没有做处理的网站,擅自发起评论,很可能会当做网络攻击,所以不要玩火,你懂得),但是这段代码却很可以说明这个过程。另外,代码中的请求头和postData里面的键我们都是可以通过开发者工具network下找到的。

    2、http.get(options,callback)######

    这个方法是http.request方法的简化版,唯一的区别是http.get自动将请求方法设为了GET请求,同时不需要手动调用req.end(),但是需要记住的是,如果我们使用http.request方法时没有调用end方法,服务器将不会收到信息。因为http.get和http.request方法都是放回一个http.ClientRequest对象,所以我们来看一下这两个对象。

    3、http.ClientRequest######

    http.ClientRequest是由http.request或者是http.get返回产生的对象,表示一个已经产生而且正在进行中的HTPP请求,提供一个response事件,也就是我们使用http.get和http.request方法中的回调函数所绑定的对象,我们可以显式地绑定这个事件的监听函数

    var http=require("http");
    
    var options={
        hostname:"cn.bing.com",
        port:80
    }
    
    var req=http.request(options);
    req.on("response",function(res){
            res.setEncoding("utf-8");
        res.on("data",function(chunk){
            console.log(chunk.toString())
        });
        console.log(res.statusCode);
    })
    
    req.on("error",function(err){
        console.log(err.message);
    });
    req.end();
    

    http.ClientRequest也提供了write和end函数,用于向服务器发送请求体,通常用于POST、PUT等操作,所有写操作都必须调用end函数来通知服务器,否则请求无效。此外,这个对象还提供了abort()、setTimeout()等方法,具体可以参考文档

    4、http.ClientReponse######

    与http.ServerRequest相似,提供了三个事件,data、end、close,分别在数据到达、传输结束和连接结束时触发,其中data事件传递一个参数chunk,表示接受到的数据。其属性如下

     
     

    此外,这个对象提供了几个特殊的函数

    • response。setEncoding([encoding]):设置默认的编码,当data事件被触发时,数据将会以encoding编码,默认值是null,也就是不编码,以buffer形式存储
    • response.pause():暂停结束数据和发送事件,方便实现下载功能
    • response.resume():从暂停的状态中恢复

    好的,到这里http模块的主要功能已经介绍完了。我们接着来做一个练习,我们知道中山大学今年院系改革,弄得我这个中大学生也不知道中大到底有那些学院了,是的,我们打开官网我们会发现有哪些学院,但是我想用http模块把里面的学院名给扒下来,好的,那我就做了以下代码

    var cheerio=require("cheerio");
    var http=require("http");
    var fs=require("fs");
    
    var options="http://www.sysu.edu.cn/2012/cn/jgsz/yx/index.htm";
    var htmlData=""
    var req=http.request(options,function(res){
        res.on("data",function(chunk){
            htmlData+=chunk;
        });
        res.on("end",function(){
            var $=cheerio.load(htmlData);
            var textcontent=$("tr").text();
            fs.writeFile("./school.txt",textcontent,"utf-8")
        });
    });
    req.end();
    

    之后我们就可在school.txt文件中看到所有的学院了,怎么样,是不是很有成就感,题外话,我这里用了一个外部的模块cheerio,这个模块可以让我们像jquery一样操作html代码,这个模块的介绍就到这里了(大家不要用这个模块的知识去干坏事哦,否则我可不负责┑( ̄Д  ̄)┍)。



    作者:忽如寄
    链接:https://www.jianshu.com/p/ab2741f78858
    來源:简书
  • 相关阅读:
    大量建置账号
    MYSQL远程登录权限设置
    设置mysql远程连接root权限
    阿里云服务器上安装mysql的心路历程(博友们进来看看哦)
    Array.Copy
    C#如何判断两个数组相等
    CentOS6.5下编译安装mysql5.6.19
    Linux下卸载和安装MySQL[rpm包]
    查看Linux磁盘空间大小
    C# 数组CopyTo
  • 原文地址:https://www.cnblogs.com/liAnran/p/9799296.html
Copyright © 2020-2023  润新知