自学内容网 自学内容网

Node.js基础

Nodejs中文文档:http://nodejs.cn/learn/how-much-javascript-do-you-need-to-know-to-use-nodejs

1. 认识Node.js

Node.js是一个javascript运行环境。它让javascript可以开发后端程序,实现几乎其他后端语言实现的所有功能。Nodejs是基于V8引擎,V8是Google发布的开源JavaScript引擎,本身就是用于Chrome浏览器的js解释部分

1.1. nodejs的特性

  • Nodejs语法完全是js语法,懂js基础就可以学会Nodejs后端开发
  • NodeJs超强的高并发能力,实现高性能服务器
  • 开发周期短、开发成本低、学习成本低

1.2. 浏览器环境vs node环境

在这里插入图片描述

Nodejs可以解析JS代码(没有浏览器安全级别的限制,提供很多系统级别的API),如:

  • 文件的读写(File System)
const fs = require('fs');
fs.readFile('./a', 'utf-8', (err, content) => {
console.log(content);
}
  • 进程的管理(Process)
function main(argv) {
console.log(argv);
}
main(process.argv.slice(2));
  • 网络通信(HTTP/HTTPS)
const http = require("http");
http.createServer((req, res) => {
res.writeHead(200, {
"Content-Type": "text/plain"
});
res.write("hello");
res.end();
}).listen(3000);

2. 开发环境搭建

http://nodejs.cn/download/

3. 模块、包、commpnJS

在这里插入图片描述

3.1. CommonJS和ES6 module区别

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • CommonJS 模块的require()是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

3.2. CommonJS

commonjs 规范应用于 nodejs 应用中,在 nodejs 应用中每个文件就是一个模块,拥有自己的作用域,文件中的变量、函数都是私有的,与其他文件相隔离。

CommonJS暴露的方式:

let name = 'node';
let obj = {
name: 'node',
age: 18
}
function say() {
console.log('good');
}
  1. exports.方法 || 属性
exports.name = name;
exports.obj = obj;
exports.say = say;

require接收:

const receive = require('./src/utils.js');
console.log(recevie); // {name: 'node', obj: {name: 'node', age: 18}, say: [Function: say]}
  1. module.exports.方法 || 属性
module.exports.name = name;
module.exports.obj = obj;
module.exports.say = say;
  1. module.exports = {方法, 属性}
    直接暴露出去一个对象,require接收到的也是一个对象
module.exports = {
name, 
obj,
say
}

注意:只要使用第三种方式暴露,就会覆盖前两种方式

3.3. ES6 module

ES6 module的导出方式

  1. export逐个导出
export let name = 'node';
export let obj = {
name: 'node',
age: 18
}
export function say() {
console.log('good');
}

接收

import {name, obj, say} from './utils.js';
  1. export{ }直接导出一个对象
let name = 'node';
let obj = {
name: 'node',
age: 18
}
function say() {
console.log('good');
}
export {name, obj, say};

接收

import * as receive from './utils.js';
  1. export default默认导出
    默认导出一个对象,不支持对象解构语法;接受时也是接收的一个对象
let name = 'node';
let obj = {
name: 'node',
age: 18
}
function say() {
console.log('good');
}
export default {
name,
obj,
say
};

接收

import receive from './utils.js';

4. 内置模块

4.1. http

const http = require('http');

// 创建本地服务器来从其接收数据
const server = http.createServer();
// 监听请求事件
server.on('request', (request, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!'
  }));
});
server.listen(8000);

4.1.1. 接口:jsonp

const http = require('http');
const url = require('url');

const app = http.createServer((req, res) => {
  let urlObj = url.parse(req.url, true);
  switch (urlObj.pathname) {
    case '/api/user':
      res.end(`${urlObj.query.cb}({"name": "gp145"})`);
      break;
    default:
      res.end('404.');
      break;
  }
});

app.listen(8080, () => {
  console.log('localhost:8080');
});

4.1.2. 跨域:cors

const http = require('http');
const url = require('url');
const querystring = require('querystring');

const app = http.createServer((req, res) => {
  let data = '';
  let urlObj = url.parse(req.url, true);
  res.writeHead(200, {
    'content-type': 'application/json;charset=utf-8',
    'Access-Control-Allow-Origin': '*',
  });
  req.on('data', (chunk) => {
    data += chunk;
  });
  req.on('end', () => {
    responseResult(querystring.parse(data));
  });
  function responseResult(data) {
    switch (urlObj.pathname) {
      case '/api/login':
        res.end(
          JSON.stringify({
            message: data,
          })
        );
        break;
      default:
        res.end('404.');
        break;
    }
  }
});

app.listen(8080, () => {
  console.log('localhost:8080');
});

4.2. url

4.2.1. parse

const url = require('url');
const urlString = 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110';
const parsedStr = url.parse(urlString);
console.log(parsedStr);

Url {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com:443',
  port: '443',
  hostname: 'www.baidu.com',
  hash: '#tag=110',
  search: '?id=8&name=mouse',
  query: 'id=8&name=mouse',
  pathname: '/ad/index.html',
  path: '/ad/index.html?id=8&name=mouse',
  href: 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
}

4.2.2. format

const url = require('url');
const urlObject = {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com:443',
  port: '443',
  hostname: 'www.baidu.com',
  hash: '#tag=110',
  search: '?id=8&name=mouse',
  query: { id: '8', name: 'mouse' },
  pathname: '/ad/index.html',
  path: '/ad/index.html?id=8&name=mouse',
};

const parsedObj = url.format(urlObject);
console.log(parsedObj); // https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110

4.2.3. resolve

const url = require('url');
const a = url.resolve('/one/two/three', 'four'); // ( 注意最后加/ ,不加/的区别 )
const b = url.resolve('http://example.com/', '/test/one');
const c = url.resolve('http://example.com/one', '/test/two');
console.log(a); // /one/two/four
console.log(b); // http://example.com/test/one
console.log(c); // http://example.com/test/two

4.3. querystring

4.3.1. parse

const querystring = require('querystring');
const qs = 'x=3&y=4';
const parsed = querystring.parse(qs);
console.log(parsed); // [Object: null prototype] { x: '3', y: '4' }

4.3.2. stringify

const querystring = require('querystring');
const qo = {
  x: 3,
  y: 4,
};
const parsed = querystring.stringify(qo);
console.log(parsed); // x=3&y=4

4.3.3. escape/unescape

const querystring = require('querystring');
const str = 'id=3&city=北京&url=https://www.baidu.com';
const escaped = querystring.escape(str);
console.log(escaped); // id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com

const str1 =
  'id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com';
const unescaped = querystring.unescape(str);
console.log(unescaped); // id=3&city=北京&url=https://www.baidu.com

4.4. event

const EventEmitter = require('events');

class MyEventEmitter extends EventEmitter {}
const event = new MyEventEmitter();

event.on('study', (movie) => {
  console.log(movie);
});
event.emit('study', 'node');

4.5. 文件操作

const fs = require('fs')

// 创建文件夹
fs.mkdir('./logs', (err) => {
  console.log('done.')
})

// 文件夹改名
fs.rename('./logs', './log', () => {
  console.log('done')
})

// 删除文件夹
fs.rmdir('./log', () => {
  console.log('done.')
})

// 写内容到文件里
fs.writeFile('./logs/log1.txt','hello',
  // 错误优先的回调函数
  (err) => {
    if (err) {
      console.log(err.message)
    } else {
      console.log('文件创建成功')
    }
  }
)

// 给文件追加内容
fs.appendFile('./logs/log1.txt', '\nworld', () => {
  console.log('done.')
})

// 读取文件内容
fs.readFile('./logs/log1.txt', 'utf-8', (err, data) => {
  console.log(data)
})

// 删除文件
fs.unlink('./logs/log1.txt', (err) => {
  console.log('done.')
})

// 批量写文件
for (var i = 0; i < 10; i++) {
  fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, (err) => {
    console.log('done.')
  })
}

// 读取文件/目录信息
fs.readdir('./', (err, data) => {
  data.forEach((value, index) => {
    fs.stat(`./${value}`, (err, stats) => {
      // console.log(value + ':' + stats.size)
      console.log(value + ' is ' + (stats.isDirectory() ? 'directory' : 'file'))
    })
  })
})

// 同步读取文件
try {
  const content = fs.readFileSync('./logs/log-1.txt', 'utf-8')
  console.log(content)
  console.log(0)
} catch (e) {
  console.log(e.message)
}

// 异步读取文件:方法一
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {
  console.log(content)
  console.log(0)
})
console.log(1)

// 异步读取文件:方法二
const fs = require("fs").promises
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {
  console.log(result)
})

因为js是单线程的,node环境执行的js代码是服务器端代码,所以,绝大部分需要在服务器运行期反复执行业务代码的逻辑,必须使用异步代码。
服务器启动时,如果需要读取配置文件,或结束时需要写入到状态文件时,可以使用同步代码,因为这些代码只在启动和结束时执行一次,不影响服务器正常运行时的异步执行。

4.6. stream流模块

在Nodejs中,流是一个对象,我们只需要响应流事件就可以了;data事件表示流的数据已经可以读取了;end事件表示这个流已经到末尾无数据可读了;error事件表示出错

const fs = require('fs');

// 打开一个流:
const rs = fs.createReadStream('sample.txt', 'utf-8');

// data事件可能会有多次,每次传递的chunk是流的一部分数据
rs.on('data', function (chunk) {
    console.log('DATA:')
    console.log(chunk);
});
rs.on('end', function () {
    console.log('END');
});
rs.on('error', function (err) {
    console.log('ERROR: ' + err);
});

要以流的形式写入文件,只需要不断调用write()方法,最后以end()结束

const  fs = require('fs');

const ws1 = fs.createWriteStream('output1.txt', 'utf-8');
ws1.write('使用Stream写入文本数据...\n');
ws1.write('END.');
ws1.end();

pipe就像可以把两个水管串成一个更长的水管一样,两个流可以串起来。一个readable流和一个writable流串起来后,所有的数据自动从readable流进入到writable流,这种操作就是pipe

const fs = require('fs')

const readstream = fs.createReadStream('./1.txt')
const writestream = fs.createWriteStream('./2.txt')
readstream.pipe(writestream)

用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件中,所以,这就是一个复制文件的程序

4.7. zlib

const fs = require('fs')
const zlib = require('zlib')

const gzip = zlib.createGzip()

const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')

readstream.pipe(gzip).pipe(writestream)

4.8. crypto

crypto模块提供了通用的加密和哈希算法

  1. md5:用于给任意数据一个签名,通常是十六进制的字符串表示
const crypto = require('crypto');

const hash = crypto.createHash('md5'); // 也可传入sha1,就表示计算SHA1

// 可任意多次调用update():
hash.update('Hello, world!');
hash.update('Hello, nodejs!');

console.log(hash.digest('hex')); 

update()方法默认字符串编码为utf-8,也可以穿入buffer
2. Hmac算法:也是一种哈希算法,可以利用md5或sha1等哈希算法。不同的是,Hmac还需要一个密钥

const crypto = require('crypto');

const hmac = crypto.createHmac('sha256', 'secret-key');

hmac.update('Hello, world!');
hmac.update('Hello, nodejs!');

console.log(hmac.digest('hex')); // 80f7e22570...

只要密钥发生了变化,那么,同样的输入会得到不同的签名。
3. AES:一种常用的对称加密算法。加解密的密钥相同。crypto需要自己封装好函数来支持AES

const crypto = require("crypto");

// key,iv必须是16个字节
function encrypt (key, iv, data) { 
    let decipher = crypto.createCipheriv('aes-128-cbc', key, iv);
    // decipher.setAutoPadding(true);
    return decipher.update(data, 'binary', 'hex') + decipher.final('hex');
}

function decrypt (key, iv, crypted) {
     crypted = Buffer.from(crypted, 'hex').toString('binary');
     let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
     return decipher.update(crypted, 'binary', 'utf8') + decipher.final('utf8');
}

5. 路由

5.1. 基础

const fs = require("fs")
const path = require("path")
function render(res, path) {
    res.writeHead(200, { "Content-Type": "text/html;charset=utf8" })
    res.write(fs.readFileSync(path, "utf8"))
    res.end()
}
const route = {
    "/login": (req, res) => {
        render(res, "./static/login.html")
    },
    "/home": (req, res) => {
        render(res, "./static/home.html")
    },
    "/404": (req, res) => {
        res.writeHead(404, { "Content-Type": "text/html;charset=utf8" })
        res.write(fs.readFileSync("./static/404.html", "utf8"))
    }
}

5.2. 获取参数

  1. get请求
    "/api/login":(req,res)=>{
        const myURL = new URL(req.url, 'http://127.0.0.1:3000');
        console.log(myURL.searchParams.get("username"))   
        render(res,`{ok:1}`)
    }
  1. post请求
"/api/login": (req, res) => {
        var post = '';
        // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
        req.on('data', function (chunk) {
            post += chunk;
        });
        // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
        req.on('end', function () {
            post = JSON.parse(post);
            render(res, `{ok:1}`)
        });
    }

5.3. 静态资源处理

function readStaticFile(req, res) {
    const myURL = new URL(req.url, 'http://127.0.0.1:3000')
    var filePathname = path.join(__dirname, "/static", myURL.pathname);
    if (fs.existsSync(filePathname)) {
        res.writeHead(200, { "Content-Type": `${mime.getType(myURL.pathname.split(".")[1])};charset=utf8` })
        res.write(fs.readFileSync(filePathname, "utf8"))
        res.end()
        return true
    } else {
        return false
    }
}

原文地址:https://blog.csdn.net/qq_36816794/article/details/142524458

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!