zoukankan      html  css  js  c++  java
  • node.js整理 04网络操作

    简介

    var http = require('http');
    
    http.createServer(function (req, res) {
      res.writeHead(200, {'Content-Type': 'text-plain'});
      res.end('Hello World
    ');
    }).listen(3000)
    
    //浏览器访问该端口http://127.0.0.1:3000/
    
    • 在Linux系统下,监听1024以下端口需要root权限。因此,如果想监听80或443端口的话,需要使用sudo命令启动程序。

    常用API

    HTTP

    • http模块提供两种使用方式:

      • 作为服务端使用时,创建一个HTTP服务器,监听HTTP客户端请求并返回响应。
      • 作为客户端使用时,发起一个HTTP客户端请求,获取服务端响应。
    • 首先需要使用.createServer方法创建一个服务器,然后调用.listen方法监听端口。之后,每当来了一个客户端请求,创建服务器时传入的回调函数就被调用一次;这是一种事件机制。

    • HTTP请求本质上是一个数据流,由请求头和请求体组成。

    POST / HTTP/1.1
    User-Agent: curl/7.26.0
    Host: localhost
    Accept: */*
    Content-Length: 11
    Content-Type: application/x-www-form-urlencoded
    
    Hello World
    
    • HTTP请求在发送给服务器时,可以认为是按照从头到尾的顺序一个字节一个字节地以数据流方式发送的。

    • 而http模块创建的HTTP服务器在接收到完整的请求头后,就会调用回调函数;在回调函数中,除了可以使用request对象访问请求头数据外,还能把request对象当作一个只读数据流来访问请求体数据。

    http.createServer(function (request, response) {
        var body = [];
    
        console.log(request.method);
        console.log(request.headers);
    
        request.on('data', function (chunk) {
            body.push(chunk);
        });
    
        request.on('end', function () {
            body = Buffer.concat(body);
            console.log(body.toString());
        });
    }).listen(80);
    
    ------------------------------------
    POST
    { 'user-agent': 'curl/7.26.0',
      host: 'localhost',
      accept: '*/*',
      'content-length': '11',
      'content-type': 'application/x-www-form-urlencoded' }
    Hello World
    
    • 为了发起一个客户端HTTP请求,需要指定目标服务器的位置并发送请求头和请求体
    var options = {
            hostname: 'www.example.com',
            port: 80,
            path: '/upload',
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
    
    var request = http.request(options, function (response) {});
    
    request.write('Hello World');
    request.end();
    
    • .request方法创建了一个客户端,并指定请求目标和请求头数据。之后,就可以把request对象当作一个只写数据流来写入请求体数据和结束请求。
    • 另外,由于HTTP请求中GET请求是最常见的一种,并且不需要请求体,因此http模块也提供了便捷API。
    http.get('http://www.example.com/', function (response) {});
    
    • 当客户端发送请求并接收到完整的服务端响应头时,就会调用回调函数。
    http.get('http://www.example.com/', function (response) {
        var body = [];
    
        console.log(response.statusCode);
        console.log(response.headers);
    
        response.on('data', function (chunk) {
            body.push(chunk);
        });
    
        response.on('end', function () {
            body = Buffer.concat(body);
            console.log(body.toString());
        });
    });
    
    ------------------------------------
    200
    { 'content-type': 'text/html',
      server: 'Apache',
      'content-length': '801',
      date: 'Tue, 05 Nov 2013 06:08:41 GMT',
      connection: 'keep-alive' }
    <!DOCTYPE html>
    ...
    

    HTTPS

    • https模块与http模块极为类似,区别在于https模块需要额外处理SSL证书。

    • 在服务端模式下,创建一个HTTPS服务器的示例如下。

    var options = {
            key: fs.readFileSync('./ssl/default.key'),
            cert: fs.readFileSync('./ssl/default.cer')
        };
    
    var server = https.createServer(options, function (request, response) {
            // ...
        });
    
    • 与创建HTTP服务器相比,多了一个options对象,通过key和cert字段指定了HTTPS服务器使用的私钥和公钥。

    • NodeJS支持SNI技术,可以根据HTTPS客户端请求使用的域名动态使用不同的证书,因此同一个HTTPS服务器可以使用多个域名提供服务

    server.addContext('foo.com', {
        key: fs.readFileSync('./ssl/foo.com.key'),
        cert: fs.readFileSync('./ssl/foo.com.cer')
    });
    
    server.addContext('bar.com', {
        key: fs.readFileSync('./ssl/bar.com.key'),
        cert: fs.readFileSync('./ssl/bar.com.cer')
    });
    
    • 但如果目标服务器使用的SSL证书是自制的,不是从颁发机构购买的,默认情况下https模块会拒绝连接,提示说有证书安全问题。在options里加入rejectUnauthorized: false字段可以禁用对证书有效性的检查,从而允许https模块请求开发环境下使用自制证书的HTTPS服务器。

    URL

    • 处理HTTP请求时url模块使用率超高,因为该模块允许解析URL、生成URL,以及拼接URL。

    • 一个完整的URL的各组成部分

                               href
     -----------------------------------------------------------------
                                host              path
                          --------------- ----------------------------
     http: // user:pass @ host.com : 8080 /p/a/t/h ?query=string #hash
     -----    ---------   --------   ---- -------- ------------- -----
    protocol     auth     hostname   port pathname     search     hash
                                                    ------------
                                                       query
    
    • 可以使用.parse方法来将一个URL字符串转换为URL对象
    url.parse('http://user:pass@host.com:8080/p/a/t/h?query=string#hash');
    /* =>
    { protocol: 'http:',
      auth: 'user:pass',
      host: 'host.com:8080',
      port: '8080',
      hostname: 'host.com',
      hash: '#hash',
      search: '?query=string',
      query: 'query=string',
      pathname: '/p/a/t/h',
      path: '/p/a/t/h?query=string',
      href: 'http://user:pass@host.com:8080/p/a/t/h?query=string#hash' }
    */
    
    • 传给.parse方法的不一定要是一个完整的URL

    • .parse方法还支持第二个和第三个布尔类型可选参数。

      • 第二个参数等于true时,该方法返回的URL对象中,query字段不再是一个字符串,而是一个经过querystring模块转换后的参数对象。
      • 第三个参数等于true时,该方法可以正确解析不带协议头的URL,例如//www.example.com/foo/bar
    • 反过来,format方法允许将一个URL对象转换为URL字符串

    url.format({
        protocol: 'http:',
        host: 'www.example.com',
        pathname: '/p/a/t/h',
        search: 'query=string'
    });
    /* =>
    'http://www.example.com/p/a/t/h?query=string'
    */
    
    • .resolve方法可以用于拼接URL
    url.resolve('http://www.example.com/foo/bar', '../baz');
    /* =>
    http://www.example.com/baz
    */
    

    Query String

    • querystring模块用于实现URL参数字符串与参数对象的互相转换
    querystring.parse('foo=bar&baz=qux&baz=quux&corge');
    /* =>
    { foo: 'bar', baz: ['qux', 'quux'], corge: '' }
    */
    
    querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' });
    /* =>
    'foo=bar&baz=qux&baz=quux&corge='
    */
    

    Zlib

    • zlib模块提供了数据压缩和解压的功能。当处理HTTP请求和响应时,可能需要用到这个模块。

    • 一个使用zlib模块压缩HTTP响应体数据的例子

    http.createServer(function (request, response) {
        var i = 1024,
            data = '';
    
        while (i--) {
            data += '.';
        }
    
        if ((request.headers['accept-encoding'] || '').indexOf('gzip') !== -1) {
            zlib.gzip(data, function (err, data) {
                response.writeHead(200, {
                    'Content-Type': 'text/plain',
                    'Content-Encoding': 'gzip'
                });
                response.end(data);
            });
        } else {
            response.writeHead(200, {
                'Content-Type': 'text/plain'
            });
            response.end(data);
        }
    }).listen(80);
    
    //这个例子中,判断了客户端是否支持gzip,并在支持的情况下使用zlib模块返回gzip之后的响应体数据。
    
    • 一个使用zlib模块解压HTTP响应体数据的例子
    var options = {
            hostname: 'www.example.com',
            port: 80,
            path: '/',
            method: 'GET',
            headers: {
                'Accept-Encoding': 'gzip, deflate'
            }
        };
    
    http.request(options, function (response) {
        var body = [];
    
        response.on('data', function (chunk) {
            body.push(chunk);
        });
    
        response.on('end', function () {
            body = Buffer.concat(body);
    
            if (response.headers['content-encoding'] === 'gzip') {
                zlib.gunzip(body, function (err, data) {
                    console.log(data.toString());
                });
            } else {
                console.log(data.toString());
            }
        });
    }).end();
    
    //判断了服务端响应是否使用gzip压缩,并在压缩的情况下使用zlib模块解压响应体数据
    

    Net

    • net模块可用于创建Socket服务器或Socket客户端; //一般更使用WebSocket

    • 一个使用Socket搭建一个很不严谨的HTTP服务器的例子。这个HTTP服务器不管收到啥请求,都固定返回相同的响应

    net.createServer(function (conn) {
        conn.on('data', function (data) {
            conn.write([
                'HTTP/1.1 200 OK',
                'Content-Type: text/plain',
                'Content-Length: 11',
                '',
                'Hello World'
            ].join('
    '));
        });
    }).listen(80);
    
    • 一个使用Socket发起HTTP客户端请求的例子
    var options = {
            port: 80,
            host: 'www.example.com'
        };
    
    var client = net.connect(options, function () {
            client.write([
                'GET / HTTP/1.1',
                'User-Agent: curl/7.26.0',
                'Host: www.baidu.com',
                'Accept: */*',
                '',
                ''
            ].join('
    '));
        });
    
    client.on('data', function (data) {
        console.log(data.toString());
        client.end();
    });
    
    //`Socket`客户端在建立连接后发送了一个`HTTP GET`请求,并通过`data`事件监听函数来获取服务器响应
    
  • 相关阅读:
    【leetcode】1215.Stepping Numbers
    【leetcode】1214.Two Sum BSTs
    【leetcode】1213.Intersection of Three Sorted Arrays
    【leetcode】1210. Minimum Moves to Reach Target with Rotations
    【leetcode】1209. Remove All Adjacent Duplicates in String II
    【leetcode】1208. Get Equal Substrings Within Budget
    【leetcode】1207. Unique Number of Occurrences
    【leetcode】689. Maximum Sum of 3 Non-Overlapping Subarrays
    【leetcode】LCP 3. Programmable Robot
    【leetcode】LCP 1. Guess Numbers
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4395652.html
Copyright © 2011-2022 走看看