Node 笔记

模块化与 npm

前端JS:与浏览器交互

后端Node.js:在服务器(和系统进行交互)端运行JS、跨平台

Node 是对 ES 标准一个实现,Node 也是一个 JS 引擎通过 Node 可以使 JS 代码在服务器端执行

Node 仅仅对 ES 标准进行了实现,所以在 Node 中不包含 DoM 和 BOM

Node 中可以使用所有的内建对象

string Number Boolean Math Date RegExp Function object Array

而 BoM 和 DOM 都不能使用

但是可以使用 console 也可以使用定时器( setTimeout () setInterval() )

Node 可以在后台来编写服务器

Node 编写服务器都是单线程的服务器

  • 进程

    进程就是一个一个的工作计划(工厂中的车间)

  • 线程

    线程是计算机最小的运算单位(工厂中的工人)
    线程是干活的

传统的服务器都是多线程的

  • 每进来一个请求,就创建一个线程去处理请求

Node 的服务器单线程的

  • Node处理请求时是单线程,但是在后台拥有一个 I/O 线程池

模块化

  • Node 中,一个 JS 文件就是一个 模块
  • Node 中,每一个 JS 文件中的 JS 代码都是独立运行在一个函数中,而不是全局作用域,所以一个模块中的变量和函数在其它模块中无法访问

向外部暴露属性或方法 exports.

var x = 'mmmmm1';
var y = 'm11111';


function f() {
    console.log('f');
}

exports.f = f;//暴露函数
exports.a = 'engureguo';//暴露属性
exports.x = x;
var m1 = require('./01.m.js');

console.log(m1);
//{ f: [Function: f], a: 'engureguo', x: 'mmmmm1' }

核心模块:服务器级别的API,被封装到包中

  • fs 文件系统工具包
  • http 服务器工具包
  • path 处理路径相关
  • os 查看CPU、内存、用户等信息
  • ...

核心模块引入

  • node引擎提供的模块
  • 核心模块标识,就是模块的名字
var fs = require('fs');

文件模块

  • 相对路径,以 . 或 .. 开头
  • 绝对路径

全局对象 global,保存全局的 属性和方法

创建全局变量:

a = 0;

global.x = 1;

验证:一个JS文件独立运行在一个函数中,而不是全局作用域,别的模块无法访问

console.log(arguments);//函数入参

console.log(arguments.callee);//当前执行的函数对象
console.log(arguments.callee + "");//查看函数实现

------------------------

function (exports, require, module, __filename, __dirname) {

var m1 = require('./01.m.js');

console.log(arguments);
console.log(arguments.callee + "");

}

实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时传递进了五个实参(global.arguments)

arguments 含义 index
exports 该对象用来将变量或函数暴露到外部 0
require 函数,用来引入外部的模块 1
module 代表当前模块本身,exports 是 module 的属性。
module.exports = exports,也可以 module.exports 导出
2
__filename 模块绝对路径 3
__dirname 模块所在文件夹 4
[Arguments] {
  '0': {},
  
  '1': [Function: require] {
    resolve: [Function: resolve] { paths: [Function: paths] },
    main: Module {
      id: '.',
      path: 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws',
      exports: {},
      parent: null,
      filename: 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\demo.js',
      loaded: false,
      children: [Array],
      paths: [Array]
    },
    extensions: [Object: null prototype] {
      '.js': [Function (anonymous)],
      '.json': [Function (anonymous)],
      '.node': [Function (anonymous)]
    },
    cache: [Object: null prototype] {
      'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\demo.js': [Module],
      'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\01.m.js': [Module]
    }
  },
  
  '2': Module {
    id: '.',
    path: 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws',
    exports: {},
    parent: null,
    filename: 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\demo.js',
    loaded: false,
    children: [ [Module] ],
    paths: [
      'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\node_modules',
      'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\node_modules',
      'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node_modules',
      'C:\\Users\\HiWin10\\Desktop\\notes\\node_modules',
      'C:\\Users\\HiWin10\\Desktop\\node_modules',
      'C:\\Users\\HiWin10\\node_modules',
      'C:\\Users\\node_modules',
      'C:\\node_modules'
    ]
  },
  
  '3': 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws\\demo.js',
  
  '4': 'C:\\Users\\HiWin10\\Desktop\\notes\\其他\\node.js\\code-ws'
}

module.exports 与 exports 的区别

module.exports 可以实现 exports 的功能,还可以:

module.exports {
    name: 'engure',
    age: 22,
	say: function() {}
}

栈内存和堆内存

var a = xxx;
var b = a;
b++;
a ? b

基本数据类型保存的数据相互独立,区别于引用类型

exports 指向 module.exports

exports = { } 相当于 exports = new Object(); 相当于修改了指向,是错误的用法

总结:

  • 通过 exports 只能使用 . 的方式向外部暴露对象
  • 通过 module.exports 既可以通过 . 的方式,有可以通过直接赋值 {}

问题:以上是讲师所讲内容,在我的机器上 node 14.17.1,可以通过 exports = {} 进行赋值

实验总结:两者的关系是开始时指向同一个对象,是引用类型,如果其中之一又创建了对象(={},或 =new Object()),那么两者指向不同

版本问题?

package.json,包的描述信息

dependencies 依赖的包

description

devDependencies 开发依赖,开发环境,区别于生产环境

directories

dist

licence

homepage

maintainers

repository

name 模块标识

...

json 文件不能写注释

NPM 包管理器

Node Package Manager

npm -v

npm version

npm search 包名

npm install 包名(install 可以简写为 i

npm init

npm remove 包名 (remove 可以简写为 r

⭐ npm install 包名 --save(安装包并安装到依赖中,--save 可简写为 -S)安装的同时将包设置在 dependencies 中,记录依赖包和他的版本,push到git上时不传 node_modules/ 中的内容

⭐ npm install 安装依赖,自动根据版本下载包

npm install -g 包名 全局安装,一般都是一些工具

如何在一个指定的目录下使用一个 npm 上的包比如 math?

  1. 初始化包 npm init (一路回车,包名不允许大写
  2. 安装 math 包 npm install math 此时 math 被安装到 node_modules
  3. 创建 index.js,引用并使用,运行 node index.js
var math = require('math');

console.log(math.add(100, 200));

CNPM

下载大包很慢,使用淘宝镜像,China NPM

npm install -g cnpm --registry=https://registry.npm.taobao.org

cnpm 命令和 npm 一样

cnpm i express -S

看到下载的文件保存方式和原来的 npm 保存方式不一样。

使用快捷方式指向包的方式,避免两者的冲突

node 搜索包的流程?⭐

node 使用模块名字来引入模块时,首先在当前目录的 node_modules 下寻找,如果找不到会去上一级继续找,如果没有则继续向上找,一直找到根目录,如果找不到则报错

commonJS 与 ES6

package.json 中定义 type 字段

  1. commonjs 默认,用于 node 环境
// util.js
exports.name = '123';
exports.age = 22;
exports.fun = function () {
    console.log('function');
}

//js.js
var { name } = require('./util.js')// 通过 { x } 部分引入
var obj = require('./util.js')  // 全部引入
console.log(name)
console.log(obj);

module.exports 与 exports 用法:https://zhuanlan.zhihu.com/p/87729137

浏览器端的应用,使用 browserify 进行语法转化

https://blog.csdn.net/dreams_deng/article/details/105655894

  1. es6 规范

大环境所致:技术变革,前后端分离,前端的业务变的越来越复杂。

es6 让 javascript 第一次支持 module(浏览器环境)

前提:使用 npm init -y 初始化包,并指定 type: module

//m1.js
var name = 'engure';
var sayHello = function () {
    console.log('hello')
}

export var name;	// 同名
export var sayHello;


//m2.js
export default {
    college: 'cup',
    type: 'undergraduate'
}


//app.js
import { name, sayHello } from './m1.js'
import * as m1 from './m1.js'
import obj from './m2.js'

console.log(name);
console.log(m1);
console.log(obj)

浏览器端的使用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
    // 定义模块
    <script type="module">			指定type!
        import { name, sayHello } from './m1.js'
        console.log(name)
    </script>
    
    
    // 引入模块
    <script type="module" src="./app.js"></script>
</html>

Buffer 与 fs 模块

Buffer

和数组很像,操作方法也相似

与数组不同的是,它能够存储二进制数据

不需要引入,Node自带,直接用

var str = 'Hello Engure!';

//将一个字符串保存到buffer中,
var buf = Buffer.from(str);

console.log(buf);
//<Buffer 48 65 6c 6c 6f 20 45 6e 67 75 72 65 21>
//范围 00~ff, 0000-0000 ~ 1111-1111,以字节为单位

buffer 占用的内存:buffer长度个字节

一个汉字占用 3 个字节

//<Buffer e7 9b 96 e7 89 b9>
console.log(Buffer.from('盖特'));

Buffer 简单使用

所有构造方法都已经废弃了

Buffer.alloc(size)

Buffer大小一旦分配,其长度固定不变,是对内存进行直接操作。(区别于数组)

//数组越界:自动分配空间
var arr = [1,2,3];
arr[5] = 5;
console.log(arr);
//[ 1, 2, 3, <2 empty items>, 5 ]

赋值&取值

var buf = Buffer.alloc(10);
buf[0] = 88;
buf[1] = 255;//ff
buf[2] = 0xaa;
buf[3] = 450;//超过255会取低8位

//查看内容
buf[2]    //默认10进制
buf[2].toString(16);  //16进制内容
buf[2].toString(2);   //2进制

//循环
for (var i=0;i<buf.length;i++) {
    console.log(buf[i].toString(16));
}

Buffer.allocUnsafe(size)

区别于 alloc(),allocUnsafe() 申请的内存是不干净的

console.log(Buffer.alloc(10));//<Buffer 00 00 00 00 00 00 00 00 00 00>
console.log(Buffer.allocUnsafe(10));//<Buffer 00 00 00 00 00 00 00 00 d8 7d>

比较

申请函数 特点
alloc(size) 获取的buffer内容都是清理干净的;效率较低
allocUnsafe(size) 可能包含内存中的“敏感数据”,是不安全的;但是效率更高

buffer.toString()

将 buffer 转化为字符串,可以查看其中的内容

console.log(buf.toString());//转为字符串类型

更多

buffer 缓冲区 http://nodejs.cn/api/buffer.html

fs 模块

文件系统 File System,通过 Node 操作文件

fs 是核心模块,不需要下载,需要引入

同步和异步的操作性形式

同步和回调

image-20210829000317672

同步文件写入

打开文件

fs.openSync(path, flags [, mode])

  • path
  • flags 打开类型,只读 rw
  • mode 设置文件权限,一般不传,多用于 linux

写入文件

fs.writeSync(fd, string [, position [, encoding] ])

  • fd 文件标识
  • string 写入内容
  • position 写入的起始位置
  • encoding 写入编码,默认 UTF-8

关闭文件描述 ⭐

fs.closeSync(fd)

注意:同步文件写入从上到下执行,需要处理异常

异步文件写入

打开文件

fs.open(path, flags [, mode], callback)

参数和同步的差不多,多了一个 callback

⭐异步函数没有返回值,返回值都是通过回调函数参数返回的

⭐回调函数参数:

  1. err 错误对象,如果没有错误则为null
  2. fd 文件的描述符
fs.open('data.txt', 'r', function (err, fd) {
    if (err != null) {//出错
        console.log(err);
    } else {
        console.log(fd);
    }
})

写入文件

fs.write(fd, string [, position [, encoding]], callback)

var fs = require('fs');

fs.open('data.txt', 'w', function (err, fd) {
    if (err != null) {//出错
        console.log(err);
    } else {
        fs.write(fd, 'HELLO啊小晶子!', function (err) {
            if (err == null) {
                console.log('写入成功~~');
            }
            
        })
    }
});

关闭文件

fs.close(fd, callback)

回调只有一个 err 参数

var fs = require('fs');

fs.open('data.txt', 'w', function (err, fd) {
    if (err != null) {//出错
        console.log(err);
    } else {
        fs.write(fd, 'HELLO啊小晶子!', function (err) {
            if (err == null) {
                console.log('写入成功~~');
            }

            //写入完成,关闭fd
            fs.close(fd, function (err) {
                if (!err) {
                    console.log("文件已经关闭~~");
                }
            })
        })
    }
});

同步:符合人类思维,较为简单

异步:不会阻塞程序的执行,性能更好,较为复杂,有一定难度

简单文件写入

封装

fs.writeFile(file, data[, options], callback)
fs.writeFileSync(file, data[, options])
  • file 路径,绝对路径或者相对路径
  • data 需要写入的数据
  • options 对象
    • encoding 编码方式
    • mode 文件权限
    • flag 文件操作类型,默认 w

异步

var fs = require('fs');
fs.writeFile('f3.txt', '简单文件写入~~', function (err) {
    if (!err) {
        console.log('写入成功~~~');
    }
});

options 对象

var fs = require('fs');
fs.writeFile('f3.txt', '简单文件写入~~', {flag:"a"}, function (err) {
    if (!err) {
        console.log('写入成功~~~');
    }
});

文件操作类型

常用:rwa

同步


流式文件写入

注意

同步、异步、简单的文件写入:不适合大文件操作

缺点:性能差,容易导致内存溢出

写入文件

fs.createWriteStream(path [, options])

用来创建一个可写流

  • path 文件路径
  • options 配置的参数,是一个对象
var fs = require('fs');

var ws = fs.createWriteStream('f5.txt');

ws.write('1.node.js\n');
ws.write('2.npm\n');
ws.write('3.cnpm\n');

事件绑定

触发多次:使用 on(事件字符串,回调函数)

触发一次:使用 once(事件字符串,回调函数)

var fs = require('fs');

var ws = fs.createWriteStream('f5.txt');

//事件触发一次,使用once绑定
ws.once('open', function () {
    console.log("打开流~~");
});
ws.once('close', function () {
    console.log("关闭流~~");
});

//可以多次写入
ws.write('1.node.js\n');
ws.write('2.npm\n');
ws.write('3.cnpm\n');

//关闭流,注意而不是 ws.close()
ws.end()

流用于写大文件

文件读取

  1. 同步文件读取
  2. 异步文件读取
  3. 简单文件读取
  4. 流式文件读取

简单文件读取

fs.readFile(path[, options], callback)

  • callback 回调函数,参数:
    • err 错误
    • data 读取的内容,是一个Buffer(考虑到二进制文件的读取)

fs.readFileSync(path[, options])

var fs = require("fs");

fs.readFile('data.txt', function (err, data) {
    if (!err) {
        console.log(data);//二进制数据
    }
});

将读取内容写入到另一文件:

var fs = require("fs");

fs.readFile('data.txt', function (err, data) {
    if (!err) {
        //console.log(data.toString());
        //将读取的文件写入另一个文件
        fs.writeFile("data2.txt", data, function (err) {
            if (!err) {
                console.log("文件写入成功~~");
            }
        });
    }

});

流式文件读取

适用于大文件读取,可以分多次将文件读取到内存中

fs.createReadStream(path[, options])

读取可读流中的数据,需要为流绑定一个关闭一个 data 事件,事件绑定完成后会自动读取数据

读取完之后,自动关闭流

var fs = require("fs");

var path = "C:\\Users\\HiWin10\\Music\\白羊.mp3";

var rs = fs.createReadStream(path);

rs.once('open', function () {
    console.log("打开流~~");
});

rs.once('close', function () {
    console.log("关闭流~~");
});

//绑定data事件,当打开流时会自动读取(分多次),读完后会触发close事件关闭流
rs.on('data', function (data) {
    console.log(data.length, data)
});
打开流~~
65536 <Buffer 49 44 33 03 00 00 00 00 00 23 54 53 53 45 00 00 00 0f 00 00 00 4c 61 76 66 35 37 2e 37 31 2e 31 30 30 00 00 00 00 00 00 00 00 00 00 00 ff fb 90 00 00 ... 65486 more bytes>
65536 <Buffer 87 43 e4 d1 f8 0a d7 90 d3 01 6b b6 9a 6d e3 3d 3f 34 8a 47 25 3c 15 a2 b8 87 a6 b4 18 ee 3c d6 7f ff b6 b5 00 00 00 2e 59 6b 64 00 63 e7 60 26 a0 02 ... 65486 more bytes>

...

65536 <Buffer bf fd 5f bb f2 35 02 05 e3 8c ef 6d ff 7e aa 07 10 bf c2 84 8d 30 54 81 81 dc eb d0 b5 81 40 cb d3 e8 22 da 46 7a 48 52 b2 14 b0 cc 14 e8 45 a7 47 a9 ... 65486 more bytes>
65536 <Buffer 5b 22 1a 22 6f ae 45 7e a2 4d a0 20 c5 09 37 9c 79 55 da 4a 62 a9 bc 06 a3 4b 89 92 04 01 d1 52 6d cd fa 7a 2c cf 28 e6 ab 98 1b e2 2e a4 db 92 bd 9d ... 65486 more bytes>
65536 <Buffer 33 dc e5 00 01 82 12 51 25 03 1c 0d 8d bc c2 32 a2 4c d8 04 92 f8 98 37 fe 67 85 71 8a 83 2b 1c b3 49 ba 61 92 b1 fd ca a1 c5 25 ea ff fb 92 64 c2 80 ... 65486 more bytes>
8904 <Buffer 76 f3 f7 7f d3 7e ac c5 75 33 e8 17 38 c9 08 33 d1 db 37 78 40 20 12 62 a0 1d 83 20 25 61 86 5e fa b4 d0 fe 76 ea b5 2e 86 2b 0f 7a df 36 cd d3 de f5 ... 8854 more bytes>
关闭流~~

将读取的文件写入文件

var fs = require("fs");

var path = "C:\\Users\\HiWin10\\Music\\白羊.mp3";

var rs = fs.createReadStream(path);

var ws = fs.createWriteStream('by.mp3')

//////////////

rs.once('open', function () {
    console.log("读流打开~~");
});

rs.once('close', function () {
    console.log("读流关闭~~");
    //读流关闭时,要顺带关闭写流
    ws.end()
});

ws.once('open', function () {
    console.log("写流打开~");
});

ws.once('close', function () {
    console.log("写流关闭~");
});

////////////////////

//读流自动读取数据,写入写流,完事后读流自动关闭,顺带关闭写流
rs.on('data', function (data) {
    ws.write(data)
});
读流打开~~
写流打开~
读流关闭~~
写流关闭~

使用 pipe() 读写文件

使用 pipe() 自动将读流与写流相关联,完成后自动关闭两者

var fs = require("fs");

var path = "C:\\Users\\HiWin10\\Music\\白羊.mp3";

var rs = fs.createReadStream(path);

var ws = fs.createWriteStream('by2.mp3')

//////////////

rs.once('open', function () {
    console.log("读流打开~~");
});

rs.once('close', function () {
    console.log("读流关闭~~");
});

ws.once('open', function () {
    console.log("写流打开~");
});

ws.once('close', function () {
    console.log("写流关闭~");
});

////////////////////

rs.pipe(ws);

不加监听事件

var fs = require("fs");
var path = "C:\\Users\\HiWin10\\Music\\白羊.mp3";

var rs = fs.createReadStream(path);//读流

var ws = fs.createWriteStream('by2.mp3');//写流

rs.pipe(ws);

服务器对请求的读取和写入就是一个流

其他内容

文件是否存在

fs.existsSync(path) 同步方法(异步方法复杂,已经废弃,不推荐)

获取文件信息

fs.stat(path, callback)

fs.statSync(path)

fs.stat("by.mp3", function () {
    console.log(arguments);
    /*
        [Arguments] {
            '0': null,
            '1': Stats {
                dev: 3430564453,
                mode: 33206,
                nlink: 1,
                uid: 0,
                gid: 0,
                rdev: 0,
                blksize: 4096,
                ino: 13229323905605598,
                size: 2695880,
                blocks: 5272,
                atimeMs: 1630205411961.7207,
                mtimeMs: 1630205383196.9993,
                ctimeMs: 1630205397322.6138,
                birthtimeMs: 1630205383184.0247,
                atime: 2021-08-29T02:50:11.962Z,
                mtime: 2021-08-29T02:49:43.197Z,
                ctime: 2021-08-29T02:49:57.323Z,
                birthtime: 2021-08-29T02:49:43.184Z
                }
        }
     */
});

可以推断

fs.stat('by.mp3', function (err, stat) {
    if (!err) {
        console.log(stat);
    }
});

fs.Statshttp://nodejs.cn/api/fs.html#fs_class_fs_stats)

  • stats.isDirectory()
  • stats.isFile()
  • stats.isSocket()
  • stats.size
  • stats.mtimeMs 最后一次修改时间
  • stats.birthtimeMs 创建时间

删除文件

fs.unlink(path, callback)

fs.unlinkSync(path)

删除文件与磁盘的连接

目录读取

fs.readdir(path [, options], callback)

fs.readSync(path [, options])

fs.readdir('.', function (err, files) {
    if (!err) {
        console.log(files);//数组
    }
});

文件截断

fs.truncate(path, len, callback)

fs.truncate(path, len)

  • len 截断 >= len 字节的内容

创建目录

fs.mkdir(path [, mode], callback)

fs.mkdirSync(path [, mode])

删除目录

fs.rmdirSync(path)

fs.rmdir(path, callback)

文件重命名

fs.rename(oldPath, newPath, callback)

fs.rename(oldPath, newPath)

fs.rename('by.mp3', 'by1.mp3', function (err) {
    if (!err){
        console.log("修改成功!");
    }
});

不同目录下,文件移动功能

//不同目录下,类似文件移动功能
fs.rename('by.mp3', 'F:/by1.mp3', function (err) {
    if (!err){
        console.log("修改成功!");
    }
});

文件的监视

fs.watchFile(filename [, options], listener)

fs.watchFile('f5.txt', function (cur, pre) {
    //console.log(arguments);
    //cur 当前的Stats
    //pre 之前的Stats
    console.log(pre.size, '->', cur.size);
});
image-20210829113234439

设置 options.interval 属性,配置轮询频率

fs.watchFile('f5.txt', {interval: 100}, function (cur, pre) {
    console.log(pre.size, '->', cur.size);
});

注意:如果设置的太小很消耗性能

http 模块

var http = require('http');

var server = http.createServer();

//注册request请求事件
server.on('request', function () {
    console.log(arguments)
});

//启动服务器,需要绑定端口号
server.listen(80, function () {
    console.log("server starting...");
});

请求处理

//注册request请求事件,回调函数需要接受两个参数
//  Request对象,获取客户端的一些信息,比如URL
//  Responce对象,用来给用户发送响应消息
server.on('request', function (req, resp) {
    console.log('请求路径 = ' + req.url);


    //write可以多次,必须以end结束,告诉给客户端写入已经结束了
    resp.write('<h1>hello node.js.</h1>');
    resp.end();
});

req.url

都是以 / 开头,是用户请求的路径

可以根据请求路径 req.url 响应不同的内容

server.on('request', function (req, resp) {
    console.log('请求路径 = ' + req.url);

    //区别对待不同的请求
    if (req.url == '/' || req.url == '/index.html' || req.url == '/index') {
        //主页
        resp.write('<h1>index</h1>');
    } else if (req.url == '/hello') {
        //hello页
        resp.write('<h2>hello bro!</h2>');
    } else {
        //404
        resp.write('<h1>page not found</h1>');
    }
    
    resp.end();
});

js 中字符串的比较 https://www.w3school.com.cn/js/js_strings.asp

Response 中的 Content-Type ⭐⭐

告诉客户端发送的内容类型

server.on('request', function (req, resp) {

    //告诉对方我发送的数据类型是什么
    resp.setHeader('Content-Type', 'text/plain; charset=utf-8');
    resp.end("hello 小郭")

});
image-20210829122440003

Content-Type 有哪些类型,表示哪些文件 https://www.runoob.com/http/http-content-type.html

Content-Type 默认类型是什么?text/html,会解析响应的html元素

如果是 text/plain 表示纯文本类型,默认不会解析html元素

image-20210829123133459

发送网页

server.on('request', function (req, resp) {

    if (req.url == '/') {
        //发送html文件
        fs.readFile("index.html", function (err, data) {
            if (err) {
                resp.setHeader('Content-Type', 'text/plain; charset=utf-8');
                resp.end("文件不存在,请重试")
            } else {
                resp.setHeader('Content-Type', 'text/html; charset=utf-8');
                resp.end(data)//参数可以是字符串也可以是Buffer,这里data是Buffer类型
            }
        });

    }
});

发送图片

server.on('request', function (req, resp) {

    if (req.url == '/') {
        //告诉对方我发送的数据类型是什么
        resp.setHeader('Content-Type', 'text/html; charset=utf-8');
        resp.write("hello 小郭<hr/>")
        resp.write("<image src='/img' />");
        resp.end()

    } else if (req.url == '/img') {
        //发送图片
        resp.setHeader('Content-Type', 'image/jpeg;');//二进制文件(图片、音频)不需要指定编码

        var rs = fs.createReadStream('5.jpg');
        rs.once('close', function () {
            resp.end()//真正关闭resp写入
        });
        rs.on('data', function (data) {
            resp.write(data)
        });

        //resp.end()异步操作,出错!Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    }
});

踩坑记录:node http fs.createReadStrem 发送文件 Error ERR_STREAM_WRITE_AFTER_END]: write after end_Engure-CSDN博客

关于设置 Content-Type:

不同类型

类型 Content-Type
纯文本 .txt text/plain; charset=utf-8
html, htm text/plain; charset=utf-8
.xml text/xml
.jpg image/jpeg
.png image/png
.gif image/gif
json格式 application/json
.pdf application/pdf
.word application/msword

编码类型

  • 对于二进制数据,不需要设置 charset
  • 对于文本类型数据 text/* ,需要设置 charset

链接

node中文文档 http://nodejs.cn/

李立超Node.js(部分)https://www.bilibili.com/video/BV1bs411E7pD

服务器开发 - 黑马 https://www.bilibili.com/video/BV1Ns411N7HU?p=7

posted @ 2023-02-28 22:21  egu0o  阅读(19)  评论(0编辑  收藏  举报