美文网首页全栈●简单课程程序员今日看点
nodejs 使用的一些http网络请求模块

nodejs 使用的一些http网络请求模块

作者: 艾伦先生 | 来源:发表于2016-11-07 23:16 被阅读7546次

    http

    大部分的node使用者,都是用node来做Web API的,而HTTP模块是提供Web API的基础。为了支持所有的HTTP应用,node中的HTTTP模块提供的API是偏向底层化的。利用HTTP模块,我们可以简单快速搭建一个Web Server。

    node提供了http这个核心模块(不用安装哦,直接require就可以了),用于创建http server服务,使用下面代码,轻松在本机的3000端口创建一个http服务器

    // http_demo.js
    var http=require("http");
    
    http.createServer(function(req,res){
        res.writeHead(200,{
            "content-type":"text/plain"
        });
        res.write("hello world");
        res.end();
    }).listen(3000);
    
    $~ node http_demo.js
    
    • 流程

      我们首先用http.createServer函数创建了一个服务器对象,然后调用了response.writeHead方法:该方法的第一个参数表示HTTP的响应状态(200)表示一切正常;第二个参数是“Content-Type”,表示我响应给客户端的内容类型。然再后我们调用了response.write方法,写入我们需要传递给客户端的内容。最后一步我们调用了response.end,表示此次请求已处理完成。

    • .listen(port)

      此函数有两个参数,第一个参数表示我们需要监听的端口,第二个参数是回调函数(其实是listening事件),当监听开启后立刻触发。

    下面我们逐步展开HTTP 的 API

    httpService (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的重要属性

    createServer方法中的参数函数中的两个参数req和res则是分别代表了请求对象和响应对象。其中req是http.IncomingMessage的实例,res是http.ServerResponse的实例。

    • http.IncomingMessage

      http.IncomingMessage是HTTP请求的信息,是后端开发者最关注的内容,一般由http.Server的request事件发送,并作为第一个参数传递,包含三个事件

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

      可以参考另一篇文章《nodejs + cheerio 爬取极客学院的nodejs课程数据》来了解http模块在爬虫中的简单应用。

    • 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 client

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

    • 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:8080
        }
        
        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();
      

      发送POST请求(模拟了向慕课网发起评论的功能,headers请使用开发者工具从请求中获取,基本上是参考scott老师的代码)

        var http=require("http");
        var querystring=require("querystring");
        
        var postData=querystring.stringify({
            "content":"just a test",
            "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("### end ##");
            });
            console.log(res.statusCode);
        });
        
        req.on("error",function(err){
            console.log(err.message);
        })
        req.write(postData);
        req.end();
      
    • http.get(options,callback)

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

    request

    可以将requset模块想象成一个简化版的第三方类http模块,同时支持https 和重定向,戳这里区官网。下文列出几个能够让你快速上手的知识点。

    安装

    npm install request --save
    var request = require('request');
    

    API

    • GET

        request(url,function(error,response,body){
            if(!error && response.statusCode == 200){
                //输出返回的内容
                console.log(body);
            }
        });
      
    • POST

        var options = { 
          uri: 'https://www.googleapis.com/urlshortener/v1/url', 
          method: 'POST', 
          json: { "longUrl": "http://www.google.com/" }
        };
      
        request({
            url: 'http://xxx.xxx.com',
            method: 'POST',
            body: formData
        }, function(error, response, body) {
            if (!error && response.statusCode == 200) {
                //输出返回的内容
                console.log(body);
            }
        });
      

    任何响应都可以输出到文件流。

    request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
    

    反过来,也可以将文件传给PUT或POST请求。未提供header的情况下,会检测文件后缀名,在PUT请求中设置相应的content-type。

    fs.createReadStream('file.json').pipe(request.put('http://mysite.com/obj.json'))
    

    表单

    request支持 application/x-www-form-urlencodedmultipart/form-data 实现表单上传。

    • x-www-form-urlencoded:

        request.post('http://service.com/upload', {form:{key:'value'}})
        或者:
        request.post('http://service.com/upload').form({key:'value'})
      
    • multipart/form-data

        var r = request.post('http://service.com/upload')
        var form = r.form()
        form.append('my_field', 'my_value')
        form.append('my_buffer', new Buffer([1, 2, 3]))
        form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png'))
        form.append('remote_file', request('http://google.com/doodle.png'))
      

    superagent

    superagent它是一个强大并且可读性很好的轻量级ajax API,是适用于nodejs环境的一个关于HTTP方面的库。

    安装

    npm install superagent --save
    

    简单使用

    一个请求的初始化可以用请求对象里合适的方法来执行,然后调用end()来发送请求。

    var superagent = require('superagent');
    
    superagent
        .post('/api')
        .send({
            'key': 'value'
        })
        .set('header_key', 'header_value')
        .end(function(err, res) {
            if (err) {
                //do something
            } else {
                //do something
            }
        })
    
    或
    superagetn
        .get(''http://example.com/search'')
        .end(function(res){ });
    

    API

    请求方法的参数可以直接使用多个key/value,也可以分多次调用请求方法每次传递一对key/valu或者key/value字符串

    • GET

          //接下来四种方法所形成的URL为/api?name=An&age=20&sex=male
          //第一种
          superagent
              .get(/api)
              .query({name:'liang'})
              .query({age:18})
              .query({sex:'female'})
              .end(function(res){ })
          //第二种
          superagent
              .get(/api)
              .query({name:'liang',age:18,sex:'female'})
              .end(function(res){ })
          //第三种 
          superagent
              .get(/api)
              .query('name=liang&age=18&sex=female')
              .end(function(res){ })
          //第四种
          superagent
              .get(/api)
              .query('name=liang')
              .query('age=18')
              .query('sex=female')
              .end(function(res){ })
      
    • POST

          superagent
              .post('/api')
              .set('Content-Type','application/json')
              .send('{"name":"An","age":20,"sex":"male"}')
              .end(cb)
          //等价于 下面的写法,因为json是默认的 Content-Type
          superagent
              .post('/api')
              .send({name:"An",age:20,sex:"male"})
              .end(cb)
          //等价于 ==>
          superagent
              .post('/api')
              .send({name:"An"})
              .send({age:20})
              .sex({sex:'male'})
              .end(cb)
      

      superagent的请求数据格式化是可以扩展的,不过默认支持form和json两种格式,想发送数据以application/x-www-form-urlencoded类型的话,则可以简单的调用.type()方法传递form参数就行,这里默认是json,下面的请求将会发送post name=a&age=18:

        request
          .post('/user') 
          .type('form') 
          .send({ name: 'tj' }) 
          .send({ pet: 'tobi' }) 
          .end(callback)
      

    post && get

    当用.send(obj)方法来发送一个post请求,并且希望传递一些查询字符串,可以调用.query()方法,比如向?format=json&dest=/login发送post请求:

    request 
      .post('/') 
      .query({ format: 'json' })
      .query({ dest: '/login' }) 
      .send({ post: 'data', msg: 'hello' }) 
      .end(callback);
    

    请求设置

    • 设置请求头:调用set()方法,参数传递一组键值对

        superagent
            .get('/api')
            .set({
                'Referer','https://www.google.com',
                'Accept','image/webp,image/*,*/*;q=0.8'
            })
             .end(function(req,res){
                //do something
            })
      
    • Response

    响应一般会提供很多有用的标识以及属性,都在response对象里,按照respone.text,解析后的response.body,头字段,一些标识的顺序来排列。

    - res.text
        包含未被解析的响应数据
    
    - res.body
        包含解析的数据,跟请求数据自动序列化一样,响应数据也会自动的解析,
        当为一个Content-Type。定义一个解析器后,就能自动解析,默认解析包
        含application/json和application/x-www-form-urlencoded,可以
        通过访问res.body来访问解析对象。
    
    - res.header
        响应头,res.header包含解析之后的响应头数据,键值都是node处理成小
        写字母形式,比如res.header['content-length'].
    
    - res.type & res.charset 类型和编码格式
        Content-Type响应头字段是一个特列,服务器提供res.type来访问它,
        默认res.charset是空的,如果有的话,则自动填充,例如Content-Type
        值为text/html; charset=utf8,则res.type为text/html,res.charst
        为utf8.
    
    - res.status状态码
    

    其他设置

    • req.abort() 终止请求

    • req.timeout(ms) 暂停请求 ms 表示毫秒为单位的时间

    • 管道数据

      nodejs客户端允许使用一个请求流来输送数据,比如请求一个文件作为输出流:

        var request = require('superagent') ,fs = require('fs');
        var stream = fs.createReadStream('path/to/my.json');
        var req = request.post('/somewhere');
        req.type('json');
        stream.pipe(req);
      

      或者输送一个响应流到文件中:

        var request = require('superagent') , fs = require('fs');
        var stream = fs.createWriteStream('path/to/my.json');
        var req = request.get('/some.json');
        req.pipe(stream);
      
    • 错误处理

      当发送错误时,superagent首先会检查回调函数的参数数量,当err参数提供的话,参数就是两个,如下:

        request 
          .post('/upload') 
          .attach('image', 'path/to/tobi.png') 
          .end(function(err, res){ });
        ``
        当省略了回调函数,或者回调只有一个参数的话,可以添加error事件的处理.
        ```js
        request 
          .post('/upload') 
          .attach('image', 'path/to/tobi.png') 
          .on('error', handle) 
          .end(function(res){ });

    相关文章

      网友评论

      • 65067d1326a2:express 不行吗
        艾伦先生:@醋溜草莓便当 :blush: 两者是有区别的。app.get('/index') app.post('/login') 是这类,是express处理请求路由的入口,比如前端有个链接 <a href="/index">,点击之后会调用通过express的app.get('/index',callback),在这个callback中处理逻辑。在这个逻辑中,如果需要发起网络请求,需要使用一个http请求库,否则直接res.render()就可以了
        65067d1326a2:@艾伦先生 我对node不太熟悉啊。不过express 貌似直接写GET[""] 或者 PUST[""] 之类的就可以获取请求了
        艾伦先生:@醋溜草莓便当 :smile: express 这个框架,具体落实到发起http请求,还是需要require()上文提到的这些网络请求库哒~
      • 153237425f19:程序猿你好啊。握爪

      本文标题:nodejs 使用的一些http网络请求模块

      本文链接:https://www.haomeiwen.com/subject/whvnuttx.html