当前位置: 首页 > news >正文

node核心学习

目录

1-1node概述

1-2全局对象

1-3Node的模块化细节

1-4Node中的ES模块化

1-5基本内置模块

OS模块:

path模块:

url模块:

util模块:

1-6文件IO

I/O:input output

fs模块的方法

代码示例:

练习:

1-7文件流

什么是流

为什么需要流

文件流

代码示例:

1-8net模块

概念:

两个主要方法:

代码示例:

练习:

1-9http模块

概念:

两个主要方法:

代码示例:

http.request(url[,option,callback]);发送一个请求。

http.createServer([options][,requestListener]);创建一个服务器。

重点总结:

练习:


1-1node概述

什么是node:

Node是一个JS的运行环境

它比浏览器拥有更多的能力:
    浏览器中的JS:
        
        web api 提供了操作浏览器窗口和页面的能力:
            BOM
            DOM
            AJAX
        这种能力是非常有限的:
            跨域问题
            文件读写


    Node中的JS:
        
        Node Api 几乎提供了所有能做的事。


    分层结构对比图:
        
        浏览器提供了有限的能力,JS只能使用浏览器提供的功能做有限的操作。
        Node提供了完整的控制计算机的能力,NodeJS几乎可以通过Node提供的接口,实现对整个操作系统的控制。

node学习地址:Node.js 中文网

我们通常用Node干什么:


    开发桌面应用程序
    开发服务器应用程序
        结构1:
            
            这种结构通常应用在微型的站点上。
            Node服务器要完成请求的处理、响应、和数据库交互、各种业务逻辑。
        结构2:
            
            这种结构非常常见,应用在各种规模的站点上。
            Node服务器不做任何与业务逻辑有关的事情。绝大部分时候,只是简单的转发请求。但可能会有一些额外的功能:
                简单的信息记录
                    请求日志
                    用户偏好
                    广告信息
                静态资源托管
                缓存

1-2全局对象

全局对象:
    setTimeout
    setInterval
    setImmediate
        类似于 setTimeout 0
    console
    __dirname
        获取当前模块所在的目录
        并非global属性
    __filename
        获取当前模块的文件路径
        并非global属性
    Buffer
        类型化数组
        继承自 UInt8Array
        计算机中存储的基本单位:字节
        使用时、输出时可能需要用十六进制表示
    process
        cwd()
            返回当前nodejs进程的工作目录
            绝对路径
        exit()
            强制退出当前node进程
            可传入退出码,0表示成功退出,默认为0
        argv
            String[]
            获取命令中的所有参数
        platform
            获取当前的操作系统
        kill(pid)
            根据进程ID杀死进程
        env
            获取环境变量对象

代码示例:

//console.log(global);//定时器
// const timer = setTimeout(() =>{});
// console.log(timer);//立即执行
//setImmediate(() => {console.log(123)});//获取当前模块所在目录的绝对路径(非global属性)
//console.log(__dirname);//获取当前模块所在文件的绝对路径(非global属性)
//console.log(__filename);//现在不太用了
// const buffer = Buffer.from("abcdefg","utf-8");
// console.log(buffer);//返回当前命令行,跟运行哪个文件的没关系,(例:在a目录下执行a/b/c.js(包含process.cwd()),返回的是a目录的绝对路径)
//console.log("当前命令行:",process.cwd());// setTimeout(() => {
//   console.log("1s后执行的");
// }, 1000);
// //强制退出进程,可传入退出码,0表示成功退出,默认为0
// process.exit(0);//获取命令行参数
//console.log(process.argv);//获取操作系统平台
//console.log(process.platform);//杀死一个进程
//console.log(process.kill(16476));//获取环境变量
//console.log(process.env);
//console.log(process.env.JAVA_HOME);

1-3Node的模块化细节

1-4Node中的ES模块化

1-5基本内置模块

OS模块:

const os = require('os');
//一行的末尾
//console.log(os.EOL);//多少位 x64 x32等
//console.log(os.arch())//获取cpu核的信息
//console.log(os.cpus().length)//获取空闲内存信息
//console.log(os.freemem() / 2^30)//获取用户目录
//console.log(os.homedir())//获取主机名
//console.log(os.hostname())//获取操作系统临时目录
console.log(os.tmpdir());

path模块:

const path = require('path');//获取文件名 (路径,[去除指定后缀名])
// const basename = path.basename("abc/abcd/abcde/a.html",".html")
// console.log(basename) //a//获取当前系统的分隔符
//console.log(path.sep); //\//获取当前系统环境变量的分隔符
//console.log(path.delimiter); //;//获取当前路径的目录名
//const dir = path.dirname("a/b/c/d/e.js")
//console.log(dir)//a/b/c/d//获取当前路径的扩展名
// const ext = path.extname("a/b/c/d/e.js")
// console.log(ext)//.js//拼接路径
// const basePath = "a/b"
// const fullpath = path.join(basePath,"../","c","d.js");
// console.log(fullpath); //a/c/d.js//获取在当前(目录或者文件)到其他(目录或者文件)的相对路径
// const rel = path.relative("/data/orandea/test/aaa","/data/orandea/impl/bbb");
// console.log(rel);//..\..\impl\bbb//获取当前路径的绝对路径(相对于命令行)
// const abs = path.resolve("./a.js");
// console.log(abs); //E:\ThePathToLearning\node\1-5.基本内置模块\a.js// const abs = path.resolve("/a.js");
// console.log(abs); //E:\a.js//获取当前路径的绝对路径(相对于当前文件)
// const abs = path.resolve(__dirname,"./a.js");
// console.log(abs);

url模块:

const URL = require("url");// const url = new URL.URL("https://www.google.com:8080/search?q=nodejs&b=1#abc");
// //const url = URL.parse("https://www.google.com:8080/search?q=nodejs&b=1#abc");
// console.log(url);
// console.log(url.searchParams.has("a")); //false
// console.log(url.searchParams.has("q")); //true
// console.log(url.searchParams.get("q")); //nodejsconst obj = {href: 'https://www.google.com:8080/search?q=nodejs&b=1#abc',origin: 'https://www.google.com:8080',protocol: 'https:',username: '',password: '',host: 'www.google.com:8080',hostname: 'www.google.com',port: '8080',pathname: '/search',search: '?q=nodejs&b=1',hash: '#abc'
}
//转换成字符串
console.log(URL.format(obj));

util模块:

const util = require("util");//普通函数
// function add(a,b){
//     return a + b;
// }
// //高阶函数
// function calculate(a,b,operation){
//     return operation(a,b);
// }
// //调用
// console.log(calculate(1,2,add));//多久后执行
// async function delay(duration = 1000){
//     return new Promise(resolve => {
//         setTimeout(() =>{
//             resolve(duration)
//         }, duration);
//     });
// }// delay(500).then(d => {
//     console.log(d);
// });//返回高阶函数
// const delayCallback = util.callbackify(delay);// delayCallback(500,(err,d)=>{
//     console.log(d+"ms后执行的");
// });// function delayCallBack(duration,callback){
//     setTimeout(() =>{
//         //回调函数,错误是null,值是duration
//         callback(null, duration);
//     }, duration);
// }// //转换为一个异步函数
// const delay = util.promisify(delayCallBack);// // delay(500).then(d => {
// //     console.log(d);
// // });
// (async () => {
//     const r = await delay(500);
//     console.log(r);
// })();const obj1 = {a:1,b:{c:3,d:{e:5}}
}const obj2 = {a:1,b:{c:3,d:{e:5,g:6}}
}//是否严格相等
console.log(util.isDeepStrictEqual(obj1,obj2))

1-6文件IO

I/O:input output

   对外部设备的输入输出。
   外部设备:磁盘,网卡,显卡,打印机,其他...
   IO的速度往往低于内存和CPU的交互速度。

fs模块的方法

读取一个文件: fs.readFile。
向文件写入内容: fs.writeFile。
获取文件或目录信息: fs.stat。

  • size: 占用字节
  • atime:上次访问时间
  • mtime:上次文件内容被修改时间
  • ctime:上次文件状态被修改时间
  • birthtime:文件创建时间
  • isDirectory():判断是否是目录
  • isFile():判断是否是文件

 获取目录中的文件和子目录:fs.readdir。
 创建目录:fs.mkdir。
 判断文件或目录是否存在:fs.exists(已弃用了)。

代码示例:

读取一个文件: fs.readFile:

const fs = require("fs")
const path = require("path")const filename = path.resolve(__dirname, "./myfiles/1.txt");
//异步读取文件,参数:文件路径,[字符集],回调函数
// fs.readFile(filename,"utf-8", (err, content) => { 
//     //console.log(data.toString("utf-8"));
//     console.log(content);
// });//同步读取文件,Sync函数是同步的,会导致JS运行阻塞,极其影响性能
//通常,在程序启动时运行有限的次数即可
// const content = fs.readFileSync(filename,"utf-8");
// console.log(content);//promises异步,基本上fs的方法,promises里面都实现
//异步读取
async function readFile(){const content = await fs.promises.readFile(filename,"utf-8");console.log(content);
}
readFile();

向文件写入内容: fs.writeFile:

const fs = require("fs")
const path = require("path")const filename = path.resolve(__dirname, "./myfiles/2.txt");async function test() {// 写入文件内容,默认UTF-8//await fs.promises.writeFile(filename, "hello world");// 追加文件内容// await fs.promises.writeFile(filename, "hello world!",{//     flag:"a" // 追加// });const buffer = Buffer.from("hello world!","utf-8");await fs.promises.writeFile(filename,buffer,{flag:"w" //覆盖});console.log("写入成功");
}test();

获取文件或目录信息: fs.stat:

const fs = require("fs")
const path = require("path")const filename = path.resolve(__dirname, "./myfiles/0001.png");async function test() {//获取文件信息const stat = await fs.promises.stat(filename);console.log(new Date(stat.birthtime).toLocaleDateString());console.log("是否是目录",stat.isDirectory())console.log("是否是文件",stat.isFile())
}test();

 获取目录中的文件和子目录:fs.readdir:

const fs = require("fs")
const path = require("path")const dirname = path.resolve(__dirname, "./myfiles/");async function test() {//返回文件列表const readdir = await fs.promises.readdir(dirname);console.log(readdir);
}test();

创建目录:fs.mkdir:

const fs = require("fs")
const path = require("path")const dirname = path.resolve(__dirname, "./myfiles/list");async function test() {//创建目录await fs.promises.mkdir(dirname);console.log("创建目录成功");
}test();

判断文件或目录是否存在:fs.exists(已弃用了):

const fs = require("fs")
const path = require("path")const dirname = path.resolve(__dirname, "./myfiles/arr");async function exists(filename){try{await fs.promises.stat(filename);return true;}catch(err){//console.dir(err)if(err.code === "ENOENT"){//文件不存在return false;}throw err;}
}async function test() {if(await exists(dirname)){console.log("目录已存在");}else{await fs.promises.mkdir(dirname);console.log("目录创建成功");}
}test();

练习:

复制文件:

const fs = require("fs")
const path = require("path")//提供文件名称复制
function copyFileName(filename){const suffix = path.extname(filename);return path.join(filename,"../",path.basename(filename,suffix)+"-copy"+suffix);
}const filename = path.resolve(__dirname, "./myfiles/0001.png");const tofilename = copyFileName(filename);async function test() {const content =  await fs.promises.readFile(filename);await fs.promises.writeFile(tofilename,content);console.log("copy success!");
}test();

复制整个目录:

const fs = require("fs")
const path = require("path")const dirname = path.resolve(__dirname, "./myfiles/");
const copyDirName = path.resolve(__dirname, "./myfilesCopy/");async function exists(filename) {try {await fs.promises.stat(filename);return true;} catch (err) {//console.dir(err)if (err.code === "ENOENT") {//文件不存在return false;}throw err;}
}async function createDir(dirname) {if (!await exists(dirname)) { //不存在,就创建await fs.promises.mkdir(dirname)}
}
//创建复制路径的目录
createDir(copyDirName);async function copyDir(filename, copydirname) {//获取目录中所有的子目录和文件const files = await fs.promises.readdir(filename);files.forEach(async (file) => {//被复制的路径 fromconst JoinFileName = path.join(filename, file);//复制的路径 toconst CopyFileName = path.join(copydirname, file);//当前文件信息const stat = await fs.promises.stat(JoinFileName);if (stat.isDirectory()) { //是目录console.log("当前目录路径:"+JoinFileName+";\n被复制的目录路径:"+CopyFileName);if(!await exists(CopyFileName)) { //不存在await fs.promises.mkdir(CopyFileName);}copyDir(JoinFileName,CopyFileName);} else if (stat.isFile()) {//是文件console.log("当前文件路径:"+JoinFileName+";\n被复制的文件路径:"+CopyFileName);const buffer = await fs.promises.readFile(JoinFileName);await fs.promises.writeFile(CopyFileName,buffer);}});
}copyDir(dirname,copyDirName);

1-7文件流

什么是流

流是指数据的流动,数据从一个地方缓缓的流动到另一个地方。
    

流是有方向的

  •     可读流: Readable数据从源头流向内存
  •     可写流: Writable数据从内存流向源头
  •     双工流: Duplex数据即可从源头流向内存,又可从内存流向源头

为什么需要流

其他介质和内存的数据规模不一致
    

其他介质和内存的数据处理能力不一致

文件流

什么是文件流:内存数据和磁盘文件数据之间的流动。

文件流的创建:

fs.createReadStream(path[, options]):
    含义:创建一个文件可读流,用于读取文件内容
    path:读取的文件路径
    options:可选配置
        encoding:编码方式
        start:起始字节
        end:结束字节
        highWaterMark:每次读取数量
            如果encoding有值,该数量表示一个字符数
            如果encoding为null,该数量表示字节数
    返回:Readable的子类ReadStream 
        事件:rs.on(事件名, 处理函数)
            open
                文件打开事件
                文件被打开后触发
            error
                发生错误时触发
            close
                文件被关闭后触发
                可通过rs.close手动关闭
                或文件读取完成后自动关闭
                    autoClose配置项默认为true
            data
                读取到一部分数据后触发
                注册data事件后,才会真正开始读取
                每次读取highWaterMark指定的数量
                回调函数中会附带读取到的数据
                    若指定了编码,则读取到的数据会自动按照编码转换为字符串
                    若没有指定编码,读取到的数据是Buffer
            end
                所有数据读取完毕后触发
        rs.pause()
            暂停读取, 会触发pause事件
        rs.resume()
            恢复读取,会触发resume事件

fs.createWriteStream(path[, options])
    创建一个写入流
    path:写入的文件路径
    options
        flags:操作文件的方式
            w:覆盖
            a:追加
            其他
        encoding:编码方式
        start:起始字节
        highWaterMark:每次最多写入的字节数
    返回:Writable的字类WriteStream
        ws.on(事件名, 处理函数)
            open
            error
            close
        ws.write(data)
            写入一组数据
            data可以是字符串或Buffer
            返回一个boolean值
                true:写入通道没有被填满,接下来的数据可以直接写入,无须排队
                    
                false:写入通道目前已被填满,接下来的数据将进入写入队列
                  
                    要特别注意背压问题,因为写入队列是内存中的数据,是有限的
            当写入队列清空时,会触发drain事件
        ws.end([data])
            结束写入,将自动关闭文件
                是否自动关闭取决于autoClose配置
                默认为true
            data是可选的,表示关闭前的最后一次写入

rs.pipe(ws):
    将可读流连接到可写流
    返回参数的值
    该方法可解决背压问题

代码示例:


fs.createReadStream(path[, options]):

const fs = require("fs");
const path =  require("path")const filename = path.resolve(__dirname, "./abc.txt");
//(path[,options])  path:读取的文件路径,options:可选配置
const rs = fs.createReadStream(filename, {encoding:"utf-8", //字符编码highWaterMark:1,//每次读几个字节autoClose:true //读完后会自动关闭(默认是true)
});//事件 rs.on(事件名,处理函数)
rs.on("open", () => { console.log("文件被打开后触发!");
});rs.on("error", () => {console.log("文件出错时触发");
});rs.on("close", () => {console.log("文件关闭时触发")
});rs.on("data", chunk => { //读取到一部分数据后触发,注册data事件后,才会真正开始读取console.log("读到了一部分数据:", chunk);rs.pause();//暂停
});rs.on("end", () => {console.log("全部数据读取完毕!");
});//rs.pause()  暂停读取,会触发pause事件
rs.on("pause", () => {console.log("暂停读取");setTimeout(() => {rs.resume();//恢复},500);
});//rs.resume()   恢复读取,会触发resume事件
rs.on("resume", () => {console.log("恢复读取");
});

fs.createWriteStream(path[, options]):

const fs = require("fs");
const path =  require("path")const filename = path.resolve(__dirname, "./temp/abc.txt");
//(path[,options])  path:读取的文件路径,options:可选配置
const ws = fs.createWriteStream(filename, {flags: "w",//a 追加,w 覆盖encoding: "utf-8",//默认UTF-8highWaterMark: 16 * 1024 //一次最多写入字节数
});ws.on("open", () => {console.log("文件被打开了");
});
ws.on("close", () => {console.log("文件被关闭了");
});
// ws.on("error", () => {
//   console.log("文件出错了");
// });//let flag = ws.write("a");
//true:写入通道没有被填满,接下来的数据可以直接写入,无须排队
//false:写入通道目前已被填满,接下来的数据进入写入队列
//console.log(flag);// flag=ws.write("a");
// console.log(flag);// flag=ws.write("a");
// console.log(flag);//导致背压问题
//1024 * 1024 * 10  ===>  10MB
// for (let i = 0; i < 1024 * 1024 * 10; i++){
//   ws.write("a");
// }//问题解决
let i = 0;
//一直写,直到到达上限,或无法再直接写入
function write() {let flag = true;while (i < 1024 * 1024 * 10 && flag) {flag = ws.write("a");i++;}
}
write();
//当写入队列清空时,会触发drain事件
ws.on("drain", () => {write();
});//结束写入,将自动关闭文件
//ws.end();

练习:复制文件:

const fs = require("fs");
const path = require("path")//方式一,内存压力大
async function method1() {const from = path.resolve(__dirname, "./temp/abc.txt");const to = path.resolve(__dirname, "./temp/abc2.txt");console.time("方式1");const content = await fs.promises.readFile(from);await fs.promises.writeFile(to,content);console.timeEnd("方式1");console.log("复制完成");
}method1();//方式二
async function method2() {const from = path.resolve(__dirname, "./temp/abc.txt");const to = path.resolve(__dirname, "./temp/abc3.txt");console.time("方式2");const rs = fs.createReadStream(from);const ws = fs.createWriteStream(to);rs.on("data", chunk => {const flag = ws.write(chunk);//写入数据if (!flag) { //当队列为空时,暂停读取rs.pause();}});ws.on("drain", () => {rs.resume();//当写入队列清空时,让rs继续读取数据});rs.on("close", () => {//写完了ws.end();//关闭写入流console.timeEnd("方式2");console.log("复制完成");});
}
method2();

rs.pipe(ws):其他封装了方式2

const fs = require("fs");
const path = require("path")//方式三
async function method2() {const from = path.resolve(__dirname, "./temp/abc.txt");const to = path.resolve(__dirname, "./temp/abc4.txt");console.time("方式3");const rs = fs.createReadStream(from);const ws = fs.createWriteStream(to);//可读流连接到可写流rs.pipe(ws);console.timeEnd("方式3");
}
method2();

1-8net模块

概念:

回顾http请求:

  • 普通模式
  • 长连接模式

net模块能干什么:

  • net是一个通信模块
  • 利用它,可以实现进程间的通信IPC和网络通信TCP/IP

两个主要方法:

net.createConnection(options[, connectListener]);创建客户端

返回一个socket

  • socket是一个特殊的文件
  • 在node中表现为一个双工流对象
  • 通过向流写入内容发送数据
  • 通过监听流的内容获取数据

net.createServer();创建服务器

返回server对象

  • server.listen(port);监听当前计算机中某个端口。
  • server.on("listening", ()=>{});开始监听端口后触发的事件。
  • server.on("connection", socket=>{});当某个连接到来时,触发该事件,事件的监听函数会获得一个socket对象。

代码示例:

net.createConnection(options[, connectListener]);

const net = require("net");//返回socket,socket是一个双工流对象
const socket = net.createConnection({host: "www.baidu.com",port: 80},() => {console.log("连接成功!");}
);/*** 提炼出响应字符串的消息头和消息体* @param {*} response */
//保存header和body的对象
var receive = null;function parseResponse(response) {//按照两次换行分割const index = response.indexOf("\r\n\r\n");//响应头const head = response.substring(0, index);//响应体,跳过两次换行的字符const body = response.substring(index + 2);//分割响应头每一项const headParts = head.split("\r\n");const headerArr = headParts.slice(1).map(str => {return str.split(":").map(s => s.trim());});//创建header为 k -> v 结构const header = headerArr.reduce((a, b) => {//b[0]是key,b[1~n]都是valuelet value = b[1];for (let i = 2; i < b.length; i++){value = value + ":" + b[i];}a[b[0]] = value;return a;}, {});return {header,body: body.trimStart()}
}function isOver() {//需要接收的消息体的总字节数const contentLength = + receive.header["Content-Length"];const curReceivedLength = Buffer.from(receive.body, "utf-8").length;//console.log(contentLength,curReceivedLength);return curReceivedLength >= contentLength;
}socket.on("data", chunk => {const response = chunk.toString("utf-8");if (!receive) { //初始化receivereceive = parseResponse(response);if (isOver()) { //第一次读取并读取完了socket.end();}return;}//添加这次获取的数据receive.body += responseif (isOver()) {socket.end();return;}
})//http格式
// socket.write(`请求行
// 请求头
//
// 请求体`);//http请求
socket.write(`GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive`);//管它有没有请求体,都要按照这个格式来socket.on("close", () => {console.log(receive.body)console.log("结束了!");
});

net.createServer();

const net = require("net");
const server = net.createServer();server.listen(9527); //服务器监听9527端口server.on("listening", () => { //监听端口事件console.log("server listen 9527")
});server.on("connection", socket => { //连接事件console.log("有客户端连接到服务器");socket.on("data", chunk => {console.log(chunk.toString("utf-8"));//重点格式里面不能有一个空格,不然会导致格式错误socket.write(`HTTP/1.1 200 OK<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><h1>你好啊!</h1>
</body>
</html>`);socket.end();});socket.on("end", () => {console.log("连接关闭了");});
});

练习:

返回不同类型的数据

解析:就是配置请求头的Content-Type类型

const net = require("net");
const server = net.createServer();
const fs = require("fs");
const path = require("path");server.listen(9527); // 服务器监听9527端口server.on("listening", () => {console.log("server listen 9527");
});server.on("connection", socket => {console.log("有客户端连接到服务器");socket.on("data", async chunk => {// console.log(chunk.toString("utf-8"));const filename = path.resolve(__dirname, "./hsq.jpg");const bodyBuffer = await fs.promises.readFile(filename);const headBuffer = Buffer.from(`HTTP/1.1 200 OK
Content-Type: image/jpeg`,"utf-8");const result = Buffer.concat([headBuffer, bodyBuffer]);socket.write(result);socket.end();});socket.on("end", () => {console.log("连接关闭了");});
});

1-9http模块

概念:

http模块建立在net模块之上:

  • 无须手动管理socket
  • 无须手动组装消息格式

两个主要方法:

  • http.request(url[,option,callback])
  • http.createServer([options][,requestListener])

代码示例:

http.request(url[,option,callback]);发送一个请求。
const http = require("http");//request -->  ClientRequest对象
//resp -->  IncomingMessage对象
const request = http.request("http://yuanjin.tech:5005/api/movie",{method: "GET"},resp => {console.log("服务器响应的状态码:", resp.statusCode);console.log("服务器响应头中的Content-Type:", resp.headers["content-type"]);console.log("服务器响应头:", resp.headers);let result = "";resp.on("data", chunk => {result += chunk.toString("utf-8");});resp.on("end", () => {console.log(JSON.parse(result));})}
);//request.write("a=1&b=2"); //一般get请求都不跟参数
request.end(); //发送消息体结束
http.createServer([options][,requestListener]);创建一个服务器。
const http = require("http");
const url = require("url");function handleReq(req) {console.log("有请求来了");const urlObj = url.parse(req.url);console.log("请求路径:", urlObj);console.log("请求方法:", req.method);console.log("请求头:", req.headers);let body = "";req.on("data", chunk => {body += chunk;});req.on("end", () => {console.log("请求体", body);});
}
//server是Server对象
//req是IncomingMessage对象
//res是ServerResponse对象
const server = http.createServer((req,res) => {handleReq(req);res.setHeader("a", "1");//设置响应头res.setHeader("b", "2"); res.statusCode = 404; //设置状态码res.write("你好!"); //设置响应体res.end();//表示写完了
},);server.listen(9527); //监听9527端口server.on("listening", () => {console.log("server listen 9527");
});

使用postman访问,或者浏览器访问。

重点总结:

我是客户端:

  • 请求:ClientRequest对象
  • 响应:IncomingMessage对象

我是服务器:

  • 请求:IncomingMessage对象
  • 响应:ServerResponse对象

练习:

写一个静态资源服务器

//静态资源服务器
// http://localhost:9527/index.html  ->   public/index.html 文件内容
//  http://localhost:9527/css/index.css  ->   public/css/index.css 文件内容const http = require("http");
const URL = require("url");
const path = require("path");
const fs = require("fs");async function getStat(filename) {try {return await fs.promises.stat(filename);} catch (err) {return null;}
}/*** 得到要处理的文件内容*/
async function getFileContent(url) {const urlObj = URL.parse(url);//要处理的文件路径let filename;//urlObj.pathname.substring(1)跳过第一个斜杠/filename = path.resolve(__dirname, "public", urlObj.pathname.substring(1));let stat = await getStat(filename);if (!stat) {//文件不存在//console.log("文件不存在");return null;}else if (stat.isDirectory()) {//文件是一个目录filename = path.resolve(__dirname,"public",urlObj.pathname.substring(1),"index.html");stat = await getStat(filename);if (!stat) {//console.log("文件不存在");return null;} else {//console.log(filename);return await fs.promises.readFile(filename);}} else {//console.log(filename);return await fs.promises.readFile(filename);}
}async function handler(req, res) {const content = await getFileContent(req.url);if (content) {res.write(content);} else {res.statusCode = 404;res.write("Resource is not exist");}res.end();
}const server = http.createServer(handler);
server.on("listening", () => {console.log("server listen 6100");
});
server.listen(6100);

相关文章:

node核心学习

目录 1-1node概述 1-2全局对象 1-3Node的模块化细节 1-4Node中的ES模块化 1-5基本内置模块 OS模块&#xff1a; path模块&#xff1a; url模块&#xff1a; util模块&#xff1a; 1-6文件IO I/O&#xff1a;input output fs模块的方法 代码示例&#xff1a; 练习…...

基于 PyQt 的YOLO目标检测可视化界面+ nuitka 打包

在人工智能和计算机视觉领域&#xff0c;YOLO&#xff08;You Only Look Once&#xff09;是一种广泛使用的实时目标检测算法。为了直观地展示YOLO算法的检测效果&#xff0c;我们使用Pyqt框架进行检测结果的可视化&#xff0c;同时为了使其能够脱离Python环境&#xff0c;我们…...

234树和红黑树

首先&#xff0c;把目光聚集在234树中 以下是234的三种节点&#xff08;可以有更多这里使用以下的三个&#xff09;&#xff1a; 右侧是节点转换成红黑树节点的样子。 接下来会用以下序列进行1234树的搭建和红黑树的搭建&#xff1a; 首先是234树 2-3-4树&#xff08;234树&…...

GenCLS++:通过联合优化SFT和RL,提升生成式大模型的分类效果

摘要&#xff1a;作为机器学习中的一个基础任务&#xff0c;文本分类在许多领域都发挥着至关重要的作用。随着大型语言模型&#xff08;LLMs&#xff09;的快速扩展&#xff0c;特别是通过强化学习&#xff08;RL&#xff09;的推动&#xff0c;对于更强大的分类器的需求也在不…...

maven坐标导入jar包时剔除不需要的内容

maven坐标导入jar包时剔除不需要的内容 问题描述解决方案 问题描述 maven坐标导入jar包时剔除不需要的内容 解决方案 Spring Boot 默认使用 Logback&#xff0c;需在 pom.xml 中排除其依赖&#xff1a; <dependency><groupId>org.springframework.boot</gro…...

Oracle OCP认证考试考点详解083系列06

题记&#xff1a; 本系列主要讲解Oracle OCP认证考试考点&#xff08;题目&#xff09;&#xff0c;适用于19C/21C,跟着学OCP考试必过。 26. 第26题&#xff1a; 题目 解析及答案&#xff1a; 关于块介质恢复&#xff0c;以下哪三项是正确的&#xff1f; A) 需恢复一个或多个…...

llfc项目分布式服务笔记

一、系统整体架构流程图(简明版) 复制代码 +---------------+ +------------------+ +----------------+ | 客户端 (Client) |--------->| GateServer |----------| StatusServer |<--+ +---------------+ +--------------…...

“链式前向星”等三种存图方式分别输出“无向无权图”的“DFS序列”

【DFS序列】 DFS序列&#xff08;深度优先搜索序列&#xff09;&#xff0c;是树或图结构在深度优先遍历过程中生成的节点访问顺序记录。 下面三段代码&#xff0c;分别采用链式前向星、邻接表、邻接矩阵存图&#xff0c;输出图的“DFS序列”。 【DFS&#xff1a;链式前向星】…...

Lesson 16 A polite request

Lesson 16 A polite request 词汇 park n. 公园&#xff0c;停车场&#xff0c;庄园 v. 停车&#xff0c;泊车 例句&#xff1a;让我来停车。    Let me park. 相关&#xff1a;spot n. 车位 区别&#xff1a;garden n. 花园 [小&#xff0c;私家的] 例句&#xff1a;我们…...

【IP101】边缘检测技术全解析:从Sobel到Canny的进阶之路

&#x1f31f; 边缘检测的艺术 &#x1f3a8; 在图像处理的世界里&#xff0c;边缘检测就像是给图像画眉毛 —— 没有它&#xff0c;你的图像就像一只没有轮廓的熊猫&#x1f43c;。让我们一起来探索这个神奇的"美妆"技术&#xff01; &#x1f4da; 目录 基础概念 …...

Nx 智能分发机制(Nx Agents + Nx Cloud)

Nx 智能分发机制&#xff08;Nx Agents  Nx Cloud&#xff09; 阶段关键做的事作用1. 收集信息- Project Graph&#xff1a;解析整个 workspace 依赖关系&#xff08;谁依赖谁&#xff09;- 历史统计&#xff1a;每次 CI 结束后将每个任务的实际用时与缓存命中情况上传…...

《“昊龙一号”:开启中国航天货运新时代》

中国航天新力量:昊龙一号登场 在 2024 年 10 月 29 日上午,神舟十九号载人飞行任务新闻发布会如一颗重磅炸弹,在航天领域激起千层浪。发布会上,一系列关乎中国载人航天工程未来走向的重要信息被披露,其中,“昊龙一号” 货运航天飞机入围空间站低成本货物运输系统总体方案…...

C++ 多态:原理、实现与应用

目录 引言 一、多态的概念 二、多态的定义及实现 &#xff08;一&#xff09;构成条件 &#xff08;二&#xff09;虚函数的深入理解 &#xff08;三&#xff09;虚函数的重写&#xff08;覆盖&#xff09; 三、抽象类 &#xff08;一&#xff09;概念 &#xff08;二&…...

多模态大语言模型arxiv论文略读(五十八)

How Does the Textual Information Affect the Retrieval of Multimodal In-Context Learning? ➡️ 论文标题&#xff1a;How Does the Textual Information Affect the Retrieval of Multimodal In-Context Learning? ➡️ 论文作者&#xff1a;Yang Luo, Zangwei Zheng, …...

TS 枚举类型

枚举 参数为枚举成员中的一个 数字枚举 字符串枚举 枚举特点 、 缺点&#xff1a;转为JS代码时会编译成JS代码&#xff0c;增大开销...

Python容器与循环:数据处理的双剑合璧

Python作为一门简洁强大的编程语言&#xff0c;其容器类型和循环结构的完美结合为数据处理提供了极大的便利。本文将带领初学者深入理解Python中的四大容器&#xff08;列表、元组、字典、集合&#xff09;以及它们与循环结构的配合使用&#xff0c;助你掌握数据处理的核心技能…...

ST-LINKV2仿真器下载

ST-LINKV2仿真器 — 正点原子资料下载中心 1.0.0 文档...

RAGFlow 接入企业微信应用实现原理剖析与最佳实践

背景 近期有医美行业客户咨询我们智能客服产品&#xff0c;期望将自己企业的产品、服务以及报价信息以企微应用的方式给到客户进行体验互动&#xff0c;提升企业运营效率。关于企业微信对接&#xff0c;我们分享下最佳实践&#xff0c;抛砖引玉。效果图如下&#xff1a; 这里也…...

大模型实践:图文解锁Ollama在个人笔记本上部署llm

使用在线模型服务时&#xff0c;我们常常需要支付API调用费用&#xff0c;这对于个人开发者或小型组织来说可能是一笔不小的开支。那么&#xff0c;有没有方法可以在本地免费使用这些强大的模型呢&#xff1f;答案是肯定的——Ollama就是这样一个工具。 当然如果是比较大的组织…...

如何提高情商?(优化版)

引言 提高情商&#xff08;EQ&#xff09;是一个需要长期练习和自我反思的过程&#xff0c;核心在于理解自己、管理情绪、共情他人并有效沟通。以下是一些具体且可操作的方法&#xff0c;结合理论和实际场景&#xff0c;帮助你逐步提升&#xff1a; 一、核心方法&#xff1a;…...

学习黑客Linux权限

在 Linux 的王国里&#xff0c;“权限”就是装备与技能加成&#xff1a;决定谁能拔剑&#xff08;读 r&#xff09;、挥剑&#xff08;写 w&#xff09;、进入房间&#xff08;执行 x&#xff09;。本文用“闯关升级”视角&#xff0c;把常见 rwx、八进制数字、SUID/SGID/Stick…...

信息系统监理师第二版教材模拟题第二组(含解析)

信息系统监理师模拟题第二组(30题) 监理理论与法规 根据《信息系统工程监理暂行规定》,监理单位应当独立于( ) A. 建设单位和承建单位 B. 政府监管部门 C. 行业组织 D. 最终用户答案:A 解析:监理单位应当保持独立性,不得与建设单位和承建单位有隶属关系或其他利害关系…...

C与指针——输入输出

错误定位 当一个库函数出错时&#xff0c;errno会被重置 perror(const char* s);\\输出s: errno 对应的错误信息 \\如果单独想要错误信息可以 char* e strerror(errno);\\系统错误码转换为对应的错误信息字符串输出缓冲区 一般输出缓冲区满的时候才刷新&#xff0c;也就是…...

RR(Repeatable Read)级别如何防止幻读

在 MySQL 数据库事务隔离级别中&#xff0c;RR&#xff08;可重复读&#xff09; 通过 MVCC&#xff08;多版本并发控制&#xff09; 和 锁机制 的组合策略来避免幻读问题。 一、MVCC机制&#xff1a;快照读与版本控制 快照读&#xff08;Snapshot Read&#xff09; 每个事务启…...

Python之学习笔记(六)

文章目录 1. 字典&#xff08;Dictionary&#xff09;2. 集合&#xff08;Set&#xff09;3. 字典 vs 集合4. 应用场景5. 注意事项 Python中的字典&#xff08; dict&#xff09;和集合&#xff08; set&#xff09;是两种高效且常用的数据结构&#xff0c;适用于不同的场景。…...

Easy云盘总结篇-文件上传02

说在前面&#xff1a;此项目是跟着B站一位大佬写的&#xff0c;不分享源码&#xff0c;支持项目付费 文件预览 主要分视频和其他文件预览&#xff0c;但实现逻辑相同&#xff0c;只是请求路径有区别。 这段逻辑&#xff1a; 拿视频预览举例&#xff1a; 视频开始时&#xff…...

window-docker的容器使用宿主机音频设备

文章目录 前言操作配置 前言 你有没有遇到过这种情况&#xff1f; 你兴冲冲地在Windows上用Docker搭了个语音识别项目&#xff0c;准备让容器高歌一曲&#xff0c;或者至少"Hey Docker"一下。结果——静音。 Docker Desktop一脸无辜&#xff1a;“亲&#xff0c;默…...

NaVILA: Legged Robot Vision-Language-ActionModel for Navigation

摘要 本文旨在解决基于视觉与语言导航&#xff08;VLN&#xff09;在四足机器人上的实现问题。该任务不仅为人类提供了一种灵活的指令方式&#xff0c;还使机器人能够在更具挑战性和杂乱的场景中导航。然而&#xff0c;将人类自然语言指令转换为低层次的腿部关节控制指令并非易…...

LeetCode 2071 你可以安排的最多任务数目 题解(附带自己的错误做题思路 过了25/49)

示例 输入&#xff1a;tasks [3,2,1], workers [0,3,3], pills 1, strength 1 输出&#xff1a;3 解释&#xff1a; 我们可以按照如下方案安排药丸&#xff1a; - 给 0 号工人药丸。 - 0 号工人完成任务 2&#xff08;0 1 > 1&#xff09; - 1 号工人完成任务 1&#…...

高翔《视觉SLAM十四讲》中第13讲,单目稠密重建中的RMODE数据集

高翔《视觉SLAM十四讲》中第13讲&#xff0c;单目稠密重建&#xff0c;中的RMODE数据集&#xff0c; 原作者苏黎世大学slam小组提供&#xff0c;但是网址已失效 下载方式&#xff1a; 1 https://vj6cqktnxq.feishu.cn/wiki/KBqtwD6XJio3Rmkm2FkckMY8nPg 2 参考地址&#xff1a…...

PyTorch_张量形状操作

搭建模型时&#xff0c;数据都是基于张量形式的表示&#xff0c;网络层与层之间很多都是以不同的shape的方式进行表现和运算。 对张量形状的操作&#xff0c;以便能够更好处理网络各层之间的数据连接。 reshape 函数的用法 reshape 函数可以再保证张量数据不变的前提下改变数…...

【浅尝Java】变量与数据类型(含隐式类型转换、强制类型转换、整型与字符串互相转换等)

&#x1f35e;自我激励&#xff1a;每天努力一点点&#xff0c;技术变化看得见 文章目录 字面常量数据类型变量变量概念语法格式整型变量字节型变量&#xff08;byte&#xff09;短整型变量&#xff08;short&#xff09;整型变量&#xff08;int&#xff09;长整型&#xff08…...

Ubuntu环境下使用uWSGI服务器【以flask应用部署为例】

0、前置内容说明 首先要知道WSGI是什么&#xff0c;关于WSGI服务器的介绍看这篇&#xff1a;WSGI&#xff08;Web Server Gateway Interface&#xff09;服务器 由于从Python 3.11开始限制了在系统级 Python 环境中使用 pip 安装第三方包&#xff0c;以避免与系统包管理器&am…...

GCC 使用指南

安装 GCC Ubuntu/Debian: sudo apt update && sudo apt install gcc gCentOS/RHEL: sudo yum install gcc gcc-cmacOS (通过 Homebrew): brew install gcc基本用法 编译 C 程序 gcc hello.c -o hello # 编译 hello.c&#xff0c;生成可执行文件 hello ./hello …...

虚函数 vs 纯虚函数 vs 静态函数(C++)

&#x1f9e9; 一图看懂&#xff1a;虚函数 vs 纯虚函数 特性虚函数&#xff08;Virtual&#xff09;纯虚函数&#xff08;Pure Virtual&#xff09;语法virtual void foo();virtual void foo() 0;是否必须实现✅ 必须在类中实现❌ 不在基类实现&#xff0c;派生类必须实现是…...

CF1000E We Need More Bosses

CF1000E We Need More Bosses 题目描述 题目大意&#xff1a; 给定一个 n n n 个点 m m m 条边的无向图&#xff0c;保证图连通。找到两个点 s , t s,t s,t&#xff0c;使得 s s s到 t t t必须经过的边最多&#xff08;一条边无论走哪条路线都经过ta&#xff0c;这条边就是…...

Python:Seaborn 美化图表的技术指南

🎨 1、简述 Seaborn 是建立在 Matplotlib 基础上的高级可视化库,提供了更美观、更简洁的数据统计图表。本文将带你深入了解 Seaborn 的强大功能,并通过多个实践案例掌握使用技巧。 2、Seaborn 1️⃣ 什么是 Seaborn? Seaborn 是一个基于 matplotlib 构建的 Python 可视…...

go实现循环链表

需求 实现循环链表的节点生成、顺序遍历、指定删除。 实现 package mainimport ("fmt" )type zodiac_sign struct {number intdizhi stringanimal stringyear intnext *zodiac_sign }// 添加 // func add_node_by_order(previous_node zodiac_sign, current_…...

QT | 常用控件

前言 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见&#x1f4dd; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 —…...

EasyExcel使用总结

EasyExcel 文章目录 EasyExcel1、导入1.1、基本方式导入1.导入依赖2. 加载源文件基本语法 3. 读取数据行4. 读取结果 1.2、模型映射导入1.定义实体映射类2. 操作读取基本语法 3. 读取数据行4. 读取结果 1.3、导入类型转换器语法 1.4、导入监听器基本语法&#xff1a; 1.5、多行…...

【形式化验证】动态逻辑(DL)的定义解释与示例

动态逻辑&#xff08;Dynamic Logic, DL&#xff09;是一种用于描述和验证程序行为的逻辑系统。它结合了命题逻辑、谓词逻辑以及模态逻辑的特点&#xff0c;特别适用于表达程序执行前后的状态变化。以下将从语法、语义以及实际应用等方面详细介绍DL公式的相关内容。 1. 动态逻…...

OpenCv实战笔记(1)在win11搭建opencv4.11.1 + qt5.15.2 + vs2019_x64开发环境

一. 准备工作 Visual Studio 2019&#xff08;安装时勾选 C 桌面开发 和 Windows 10 SDK&#xff09; CMake 3.20&#xff08;官网下载&#xff09; Qt 5.15.2&#xff08;下载 Qt Online Installer&#xff09;安装时勾选 MSVC 2019 64-bit 组件。 opencv 4.11.1 源码下载 git…...

四年级数学知识边界总结思考-上册

目录 一、背景二、过程1.大数的认识**一、知识点梳理****二、知识点的由来****三、作用与意义****四、总结** 2. 公顷和平方千米**一、知识点梳理****二、知识点的由来****三、作用与意义** 3.角的度量**一、知识点梳理****二、知识点的由来****三、作用与意义** 4.平行四边形和…...

(undone) MIT6.S081 2023 学习笔记 (Day10: LAB9 fs file system)

url: https://pdos.csail.mit.edu/6.1810/2023/labs/fs.html 任务1&#xff1a;Large files (moderate) ----------------- 完成 本次作业中&#xff0c;你将扩大xv6文件的最大容量。当前xv6文件被限制为268个块&#xff08;即268*BSIZE字节&#xff0c;xv6中BSIZE为1024&…...

SpringMVC详解

一&#xff1a;Maven 1.1 概述 &#xff08;1&#xff09;项目结构 所有IDE使用Maven创建的项目结构完全一样&#xff0c;maven项目可通用 &#xff08;2&#xff09;构建流程&#xff08;编译、测试、打包、发布&#xff09; &#xff08;3&#xff09;依赖管理 定义&#xff…...

【Python】一直没搞懂生成器是什么。。

生成器 上期我们讲解了迭代器:【Python】一直没搞懂迭代器是什么。。-CSDN博客 这期我们来讲讲它的好兄弟——生成器 生成器 (Generator)? 生成器是一种特殊的 迭代器 (Iterator)。 迭代器 是你可以逐个访问其元素的对象(比如在 for 循环中使用)。列表、元组、字典、字符…...

高等数学同步测试卷 同济7版 试卷部分 上 做题记录 第四章 不定积分同步测试卷 B卷

第四章 不定积分同步测试卷 B卷 一、单项选择题(本大题共5小题,每小题3分,总计15分) 1. 2. 3. 4. 5. 二、填空题(本大题共5小题,每小题3分,总计15分) 6. 7. 8. 9. 10. 三、求解下列各题(本大题共5小题,每小题6分,总计30分) 11. 12. …...

只用Prettier进行格式化项目

1.下载Prettier插件&#xff0c;禁用ESlint 2.在项目根目录新建.prettierrc文件 {"singleQuote": true,"jsxSingleQuote": true,"printWidth": 100,"trailingComma": "none","tabWidth": 2,"semi": f…...

ARM寻址方式

寻址方式指的是确定操作数位置的方式。 寻址方式&#xff1a; 立即数寻址 直接寻址&#xff08;绝对寻址&#xff09;&#xff0c;ARM不支持这种寻址方式&#xff0c;但所有CISC处理器都支持 寄存器间接寻址 3种寻址方式总结如下&#xff1a; 助记符 RTL格式 描述 ADD r0,r1…...

2025年- H25-Lc133- 104. 二叉树的最大深度(树)---java版

1.题目描述 2.思路 返回左右子树中&#xff0c;最高高度的子树,高度从0开始计数。 3.代码实现 class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val val;…...