Node-2

作者: hellomyshadow | 来源:发表于2019-04-21 10:38 被阅读0次

path模块

path模块:用于处理文件路径,var path = require('path')

  1. path.extname('index.html'):获取文件的后缀名 .html
  2. path.basename('./conf/img/a.png'):获取文件名 a.png
  3. path.join(path1, path2, ...):连接路径,它会正确地使用当前系统的路径分隔符,Unix系统是 /Windows系统是 \
  4. path.parse(pathStr):返回路径字符串的对象;
  5. path.resolve(from, to):将相对路径转为绝对路径。

url模块

  1. 解析一个域名
    var url = require('url')
    var result = url.parse('http://www.baidu.com/')
    
  2. result是一个对象,如获取协议名:result.protocol --> http
  3. url.parse('http://www.a.com/news?n=pfy&a=10', true):GET 请求的参数封装成一个对象
    query: { n: 'pfy', a: '10' }
    
  4. url.format():url.parse()的逆向操作
  5. url.resolve(from, to):拼接URL
    url.resolve('http://abc.com', 'one')  // http://abc.com/one
    url.resolve('http://abc.com/news', 'one')  // http://abc.com/one
    

http模块

  1. http模块:提供了网络请求(客户端)和网络服务(服务端)的实现;
  2. http服务端:http.Server 继承自 net.Server
    const server = new http.Server(); / http.createServer();
    server.listen(8000, '127.0.0.1', ()=>{
     // 启动成功的回调 
    });
    
    1. 接收请求的事件
      server.on('request', (req, res) => {  // request, response
         let url = req.url;   // 请求地址,对应服务端的路由
      });
      
    2. req 本质是 net.Socket + (http协议增加的内容)req.socket 获取客户端的socket对象
    3. 设置响应头:res.writeHead(状态码, 状态描述, 响应头);
      res.writeHead(200, 'ok', {
         'Content-Type': 'text/html;charset=utf8'
      });
      res.writeHead(301, http.STATUS_CODES[301], { --->重定向
         'Content-Type': 'text/html;charset=utf8',
         'Location': '/'  ----> 告诉浏览器重定向的地址
      });
      
    4. res.setHeader(key, val);也是设置响应头,会与 writeHead() 设置的响应头合并,且 writeHead() 设置的响应头优先;响应头的设置必须在响应数据之前;
    5. 设置响应数据:res.write('hello client');
    6. 把数据响应给客户端:
      res.end();   // 本次响应数据输出完成
      // 如果传递参数,内部会调用 write()
      res.end('hello client');
      
      • res.end() 表示输出,是因为 response 本质上是流操作;
      • 通过递归查看 response 的原型链:Object.getPrototypeOf(response) 可知,responseStream(流) 的原型链上。
  3. Http服务的简写形式:
     http.createServer((req, res) => {
         ...
     }).listen(8000);
    
    • req - request 包含所有的请求信息,如req.url 请求接口,req.headers 请求头;
    • res - response 响应对象。
    • 接收请求体
      let reqData = [], size = 0
      req.on('data', data => {
          reqData.push(data)
          size += data.length
      })
      req.on('end', () => {  // 读取完成
          // 获取到请求体的Buffer
          const data = Buffer.concat(reqData, size)
          // 结束响应
          res.end()
      })
      
    • 处理对 静态资源 请求,如图片
      const server = http.createServer((req, response) => {
          if(req.headers.accept.indexOf('image/*') !== -1) {
              // 通过请求头判断是 图片资源,创建一个读取流
              const fs = fs.createReadStream('./b.jpg')
              // 通过读写流管道直接写入响应体,response是一个写入流
              fs.pipe(response)
          } else {
              response.end('hello node')
          }
      })
      
  4. http客户端:http.request();
    1. 发起一个 http 请求
      let client = http.request({
            host: '127.0.0.1',
            port: 8000,   // IP和端口号是TCP所必须的,其他的参数是http所需要的
            protocol: 'http:',
            method: 'get',
            path: '/abc'   // get请求的完整地址:http://127.0.0.1:8000/abc
      }, res => {   // 处理服务器的响应数据
            res.on('data', data => {
                     ...//处理接收的数据,数据量比较大时,socket会分包发送,data事件多次触发
            });
            res.on('end', () => {
                     //数据传输完成
            });
      });
      
    2. 发送的数据,并通知服务器发送完成
      client.write('hello server');  // 比如post请求的参数
      client.end();
      

作为客户端

  1. 发送POST请求,接收响应的ZIP数据流
let params = {}
let options = {
    hostname: '117.78.51.252', port: 8030, method: "POST", // POST请求
    path: '/Ae/Resources/Download', // 接口
    headers: { }  // 如果需要,可以手动设置请求头
}
let streamlist = [];
let req = http.request(options, res => {
    //res.setEncoding('utf8')  //当请求的是流数据时,一定不能设置响应数据的编码
    res.on('data', chunk => {  // 接收数据
        streamlist.push(chunk);  //大数据流会分多次传输,所以先用数组保存
    });
    res.on('end', () => {
        let data = Buffer.concat(streamlist);  // 把一个buffer数组转为一个buffer
        fs.writeFile('./config.zip', data, err=>{})  //把Buffer写入到文件中
    });
});
req.on('error', e => { console.error(`请求遇到问题: ${e.message}`); });
// 把参数转化后,写入请求主体,两种转化方式,根据后台的获取方式进行选择
let postData = require('querystring').stringify(params)  // id=1&name=Mack
let postData = JSON.stringify(params)  // {"id":1,"name":"Mack"}
req.write(postData);
req.end();  // 告诉服务器,结束请求
  1. POST请求上传文件
let boundaryKey = "----" + new Date().getTime();  // HTTP协议
let options = {
    hostname: '117.78.51.252', port: 8030, method: "POST",
    path: '/Ae/Project/Upload',
    headers: {   // 设置数据的类型:multipart/form-data表示是上传文件
        "Content-Type": "multipart/form-data; boundary=" + boundaryKey,
        'Connection': "keep-alive"
    }
};
let req = http.request(options, function(res) {
    res.setEncoding("utf8");  // 设置响应数据的编码格式
    res.on("data", chunk => {  // chunk其实是一个Buffer
        console.log(chunk.toString())  // 假设响应数据是简短的JSON字符串
    });
    res.on("end", () => { console.log("res end."); });
});
req.on('error', e => { console.log('req error: ', e) });
//开始上传:参数1表示提交的内容信息,参数2表示上传的文件列表,参数3表示请求对象
this.postFile([], [{ urlKey:"file1",   /**文件名*/  urlValue: './config.zip'  /**文件的路径*/ }], req);

postFile(fileInfo, fileData, req) {
    const path = require('path'), fs = require('fs');
    let boundaryKey = Math.random().toString(16);
    let enddata = '\r\n----' + boundaryKey + '--';
    let dataLength = 0, dataArr = new Array();
    for (let i = 0; i < fileInfo.length; i++) {
        let dataInfo = "\r\n----" + boundaryKey + "\r\n" + "Content-Disposition: form-data; name=\""
                       + fileInfo[i].urlKey + "\"\r\n\r\n" + fileInfo[i].urlValue;
        let dataBinary = new Buffer(dataInfo, "utf-8");
        dataLength += dataBinary.length;
        dataArr.push({ dataInfo });
    }
    let files = new Array();
    for (let i = 0; i < fileData.length; i++) {
        let content = "\r\n----" + boundaryKey + "\r\n" + "Content-Type: application/octet-stream\r\n" + 
            "Content-Disposition: form-data; name=\"" + fileData[i].urlKey + "\"; filename=\"" + 
            path.basename(fileData[i].urlValue) + "\"\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n";
        //编码为ascii时,中文会乱码
        let contentBinary = new Buffer(content, 'utf-8');
        files.push({ contentBinary, filePath: fileData[i].urlValue });
    }
    let contentLength = 0;
    for (let i = 0; i < files.length; i++) {
        let filePath = files[i].filePath;
        if (fs.existsSync(filePath)) {
            let stat = fs.statSync(filePath);
            contentLength += stat.size;
        } else {
            contentLength += new Buffer("\r\n", 'utf-8').length;
        }
        contentLength += files[i].contentBinary.length;
    }
    req.setHeader('Content-Type', 'multipart/form-data; boundary=--' + boundaryKey);
    req.setHeader('Content-Length', dataLength + contentLength + Buffer.byteLength(enddata));
    // 将参数发出
    dataArr.forEach(({ dataInfo }) => req.write(dataInfo))
    let fileindex = 0;
    let doOneFile = function () {
        req.write(files[fileindex].contentBinary);
        let currentFilePath = files[fileindex].filePath;
        if (fs.existsSync(currentFilePath)) {
            let fileStream = fs.createReadStream(currentFilePath, { bufferSize: 4 * 1024 });
            fileStream.pipe(req, { end: false });
            fileStream.on('end', () => {
                fileindex++;
                if (fileindex == files.length) {
                    req.end(enddata);
                } else {
                    doOneFile();
                }
            });
        } else {
            req.write("\r\n");
            fileindex++;
            if (fileindex == files.length) {
                req.end(enddata);
            } else {
                doOneFile();
            }
        }
    };
    if(fileindex == files.length) {
        req.end(enddata);
    } else {
        doOneFile();
    }
}
  1. request模块 是对http模块的GET、POST等请求的进一步封装。

相关文章

网友评论

      本文标题:Node-2

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