Node.js心得笔记
npm init 可用npm 来调试node项目
浏览器中的顶级对象时window
<ref *1> Object [global] { global: [Circular *1], clearImmediate: [Function: clearImmediate], setImmediate: [Function: setImmediate] { [Symbol(nodejs.util.promisify.custom)]: [Getter] }, clearInterval: [Function: clearInterval], clearTimeout: [Function: clearTimeout], setInterval: [Function: setInterval], setTimeout: [Function: setTimeout] { [Symbol(nodejs.util.promisify.custom)]: [Getter] }, queueMicrotask: [Function: queueMicrotask], structuredClone: [Function: structuredClone], atob: [Getter/Setter], btoa: [Getter/Setter], performance: [Getter/Setter], fetch: [Function: fetch], crypto: [Getter] }
node中的顶级对象时global
module.exports 与 require
const GetName = ()=>{ return "jack" ; }; const GetAge = ()=>{ return 18; }; module.exports = { GetName, GetAge }
const {GetName,GetAge} = require("./utils"); GetName(); GetAge();
默认情况下,Node.js 将 JavaScript 文件视为 CommonJS 模块,需要使用:module.exports ={} 和 require 来导出导入。若使用export 与 import 报错,需要将package.js中的:"type": "commonjs", 转成 type": "module"
export default = methods 更适用于单个组件进行导出,可以随意命名,并且一个js文件中只能有一个默认导出
export = {...methods} 更适用于多个方法的导出,不能随意命名,但可以通过 import {methodName as methodSetName} 来进行命名,一个js文件中可有多个普通导出
值得注意的是,在一个js文件中,可以同时有多个普通导出与一个默认导出。
后端server配置CORS ,允许前端跨域发起请求
同源策略是一个安全机制,要求“协议+域名+端口”三者相同,否则浏览器会阻止网页向不同源的服务器发送请求。
// Add CORS headers,允许跨域 res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5173'); //'http://localhost:5173/' 会报错,不能加,因为这个CORS是根据字符串来匹配的 // 允许所有源 res.setHeader('Access-Control-Allow-Origin', '*'); // 也可以根据请求源动态设置,允许信任的请求源 const allowedOrigins = ['http://localhost:5173', 'https://yourapp.com', 'http://127.0.0.1:8080']; const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin); } res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
若前端在请求头中自定义了某个属性,你需要在后台服务器中的CORS也定义上:
//前端 axios.get('http://localhost:8888/', { headers: { 'X-Custom-Header': 'foobar' } }) //后台服务器 res.setHeader('Access-Control-Allow-Headers','Content-Type, Authorization, X-Custom-Header');
避免修改一次代码就要重启一次服务器
npm install nodemon
package-lock.js 是依赖项文件夹,类似于python中的requirement.txt,执行npm install 可下载所有的依赖项。并会将所有的依赖项存储到文件夹node_modules里。同时,npm i 也能完成更新依赖包的作用。作用是为了防止将依赖包都放到github上
也可以在.gitignore中添加不推送到github中的文件夹/文件名
.gitignore | node_modules | ...all_requirement_packages
配置package.json文件,完成使用nodemon 来调试程序。
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "dev": "nodemon server.js" },
.env文件
用于设置项目中的全局变量,不能有空格
PORT=8080
//实际使用 const PORT = process.env.PORT;
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "dev": "nodemon --env-file=.env server.js" },
必须要加 --env-file=.env,否则指定的全局变量会显示undefined
并且可以在.gitignore文件中,添加.env ,防止上传到git
原生的node.js服务端
import http from 'http'; // const PORT = process.end.PORT; const PORT = process.env.PORT; const server = http.createServer((req, res) => { // Add CORS headers,解决跨域问题 res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5173'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Custom-Header'); //debug console.log(req.url); //客户端请求的网址 console.log(req.method); //客户端的请求方式 // For normal requests, proceed with your existing code res.writeHead(200, "OK", { 'Content-Type': 'text/html' }); res.write( `<h1>hello user</h1> <h2>Welcome to http my server</h2> <h3>Wish you have a good day</h3> ` ); res.end(JSON.stringify({ "message": "ok", "statusCode": 200, "data": { "name": "Jack", "age": 18, "home":"ShangHai", } })); }); server.listen(PORT, () => { console.log(`use ${PORT} port ,search: http://localhost:${PORT}/`); });
客户端像后端发起get请求,为什么后台打印:OPTIONS GET
这是由于:CORS预检机制
当浏览器发起跨域请求时,会触发CORS(跨源资源共享)机制。在特定情况下,浏览器会在实际请求前自动发送一个"预检请求"(OPTIONS请求),这就是您在后台看到OPTIONS和GET两个请求的原因。
关于Access-Control-Max-Age的详细说明
这个头部信息的作用是告诉浏览器在指定的时间内(以秒为单位)可以缓存预检请求的结果,而无需再次发送OPTIONS请求。这对于优化性能非常有益,特别是在频繁发生跨域请求的应用中。
浏览器限制:不同浏览器对Access-Control-Max-Age的最大值有不同限制:
-
Chrome: 最大值为7200秒(2小时)
-
Firefox: 最大值为86400秒(24小时)
-
Safari: 没有明确限制,但遵循标准建议
将获取当前文件的路径
import fs from 'fs/promises'; import url from 'url'; import path from 'path'; //get current path //import.meta.url 当前路径的url export const GetCurrentPath = (importUrl) =>{ const fileName = url.fileURLToPath(importUrl); //将文件的url转化为路径 const dirName = path.dirname(fileName); //输入:文件的路径;输出:文件所在目录 return { fileName, dirName } } console.log(import.meta.url); //file:///C:/Users/32217/Desktop/%E9%A1%B9%E7%9B%AE/%E5%8C%BB%E7%96%97%E5%81%A5%E5%BA%B7%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/code/front-end/server.js console.log(fileName); console.log(dirName); /* C:\Users\32217\Desktop\项目\医疗健康管理系统\code\front-end\server.js C:\Users\32217\Desktop\项目\医疗健康管理系统\code\front-end */
response.writeHead() 与 response.end() 必须配套使用,否则会响应超时!!!
Request
C:\Users\32217\Desktop\项目\医疗健康管理系统\code\front-end\public\404.html Using port 8888, visit: http://localhost:8888/ req.url:/Login req.method:POST <ref *2> IncomingMessage { _events: { close: undefined, error: undefined, data: undefined, end: undefined, readable: undefined }, _readableState: ReadableState { highWaterMark: 16384, buffer: [], bufferIndex: 0, length: 0, pipes: [], awaitDrainWriters: null, [Symbol(kState)]: 1315084 }, _maxListeners: undefined, socket: <ref *1> Socket { connecting: false, _hadError: false, _parent: null, _host: null, _closeAfterHandlingError: false, _events: { close: [Array], error: [Function: socketOnError], prefinish: undefined, finish: undefined, drain: [Function: bound socketOnDrain], data: [Function: bound socketOnData], end: [Array], readable: undefined, timeout: [Function: socketOnTimeout], resume: [Function: onSocketResume], pause: [Function: onSocketPause] }, _readableState: ReadableState { highWaterMark: 16384, buffer: [], bufferIndex: 0, length: 0, pipes: [], awaitDrainWriters: null, [Symbol(kState)]: 193997060 }, _writableState: WritableState { highWaterMark: 16384, length: 0, corked: 0, onwrite: [Function: bound onwrite], writelen: 0, bufferedIndex: 0, pendingcb: 0, [Symbol(kState)]: 17564420, [Symbol(kBufferedValue)]: null }, allowHalfOpen: true, _maxListeners: undefined, _eventsCount: 8, _sockname: null, _pendingData: null, _pendingEncoding: '', server: Server { maxHeaderSize: undefined, insecureHTTPParser: undefined, requestTimeout: 300000, headersTimeout: 60000, keepAliveTimeout: 5000, connectionsCheckingInterval: 30000, requireHostHeader: true, joinDuplicateHeaders: undefined, rejectNonStandardBodyWrites: false, _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _connections: 1, _handle: [TCP], _usingWorkers: false, _workers: [], _unref: false, _listeningId: 2, allowHalfOpen: true, pauseOnConnect: false, noDelay: true, keepAlive: false, keepAliveInitialDelay: 0, highWaterMark: 16384, httpAllowHalfOpen: false, timeout: 0, maxHeadersCount: null, maxRequestsPerSocket: 0, _connectionKey: '6::::8888', [Symbol(IncomingMessage)]: [Function: IncomingMessage], [Symbol(ServerResponse)]: [Function: ServerResponse], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(async_id_symbol)]: 245, [Symbol(kUniqueHeaders)]: null, [Symbol(http.server.connections)]: ConnectionsList {}, [Symbol(http.server.connectionsCheckingInterval)]: Timeout { _idleTimeout: 30000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 191, _onTimeout: [Function: bound checkConnections], _timerArgs: undefined, _repeat: 30000, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 248, [Symbol(triggerId)]: 246 } }, _server: Server { maxHeaderSize: undefined, insecureHTTPParser: undefined, requestTimeout: 300000, headersTimeout: 60000, keepAliveTimeout: 5000, connectionsCheckingInterval: 30000, requireHostHeader: true, joinDuplicateHeaders: undefined, rejectNonStandardBodyWrites: false, _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _connections: 1, _handle: [TCP], _usingWorkers: false, _workers: [], _unref: false, _listeningId: 2, allowHalfOpen: true, pauseOnConnect: false, noDelay: true, keepAlive: false, keepAliveInitialDelay: 0, highWaterMark: 16384, httpAllowHalfOpen: false, timeout: 0, maxHeadersCount: null, maxRequestsPerSocket: 0, _connectionKey: '6::::8888', [Symbol(IncomingMessage)]: [Function: IncomingMessage], [Symbol(ServerResponse)]: [Function: ServerResponse], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(async_id_symbol)]: 245, [Symbol(kUniqueHeaders)]: null, [Symbol(http.server.connections)]: ConnectionsList {}, [Symbol(http.server.connectionsCheckingInterval)]: Timeout { _idleTimeout: 30000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 191, _onTimeout: [Function: bound checkConnections], _timerArgs: undefined, _repeat: 30000, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 248, [Symbol(triggerId)]: 246 } }, parser: HTTPParser { '0': null, '1': [Function: parserOnHeaders], '2': [Function: parserOnHeadersComplete], '3': [Function: parserOnBody], '4': [Function: parserOnMessageComplete], '5': [Function: bound onParserExecute], '6': [Function: bound onParserTimeout], _headers: [], _url: '', socket: [Circular *1], incoming: [Circular *2], outgoing: null, maxHeaderPairs: 2000, _consumed: true, onIncoming: [Function: bound parserOnIncoming], joinDuplicateHeaders: null, [Symbol(resource_symbol)]: [HTTPServerAsyncResource] }, on: [Function: socketListenerWrap], addListener: [Function: socketListenerWrap], prependListener: [Function: socketListenerWrap], setEncoding: [Function: socketSetEncoding], _paused: false, _httpMessage: ServerResponse { _events: [Object: null prototype], _eventsCount: 1, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: false, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: true, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: null, _hasBody: true, _trailer: '', finished: false, _headerSent: false, _closed: false, socket: [Circular *1], _header: null, _keepAliveTimeout: 5000, _onPendingData: [Function: bound updateOutgoingData], req: [Circular *2], _sent100: false, _expect_continue: false, _maxRequestsPerSocket: 0, [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, [Symbol(async_id_symbol)]: 250, [Symbol(kHandle)]: TCP { reading: true, onconnection: null, _consumed: true, [Symbol(owner_symbol)]: [Circular *1] }, [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: null, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kSetNoDelay)]: true, [Symbol(kSetKeepAlive)]: false, [Symbol(kSetKeepAliveInitialDelay)]: 0, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0 }, httpVersionMajor: 1, httpVersionMinor: 1, httpVersion: '1.1', complete: false, rawHeaders: [ 'Host', 'localhost:8888', 'Connection', 'keep-alive', 'Content-Length', '45', 'sec-ch-ua-platform', '"Windows"', 'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', 'Accept', 'application/json, text/plain, */*', 'sec-ch-ua', '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"', 'Content-Type', 'application/json', 'X-Custom-Header', 'foobar', 'sec-ch-ua-mobile', '?0', 'Origin', 'http://localhost:5173', 'Sec-Fetch-Site', 'same-site', 'Sec-Fetch-Mode', 'cors', 'Sec-Fetch-Dest', 'empty', 'Referer', 'http://localhost:5173/', 'Accept-Encoding', 'gzip, deflate, br, zstd', 'Accept-Language', 'zh-CN,zh;q=0.9' ], rawTrailers: [], joinDuplicateHeaders: null, aborted: false, upgrade: false, url: '/Login', method: 'POST', statusCode: null, statusMessage: null, client: <ref *1> Socket { connecting: false, _hadError: false, _parent: null, _host: null, _closeAfterHandlingError: false, _events: { close: [Array], error: [Function: socketOnError], prefinish: undefined, finish: undefined, drain: [Function: bound socketOnDrain], data: [Function: bound socketOnData], end: [Array], readable: undefined, timeout: [Function: socketOnTimeout], resume: [Function: onSocketResume], pause: [Function: onSocketPause] }, _readableState: ReadableState { highWaterMark: 16384, buffer: [], bufferIndex: 0, length: 0, pipes: [], awaitDrainWriters: null, [Symbol(kState)]: 193997060 }, _writableState: WritableState { highWaterMark: 16384, length: 0, corked: 0, onwrite: [Function: bound onwrite], writelen: 0, bufferedIndex: 0, pendingcb: 0, [Symbol(kState)]: 17564420, [Symbol(kBufferedValue)]: null }, allowHalfOpen: true, _maxListeners: undefined, _eventsCount: 8, _sockname: null, _pendingData: null, _pendingEncoding: '', server: Server { maxHeaderSize: undefined, insecureHTTPParser: undefined, requestTimeout: 300000, headersTimeout: 60000, keepAliveTimeout: 5000, connectionsCheckingInterval: 30000, requireHostHeader: true, joinDuplicateHeaders: undefined, rejectNonStandardBodyWrites: false, _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _connections: 1, _handle: [TCP], _usingWorkers: false, _workers: [], _unref: false, _listeningId: 2, allowHalfOpen: true, pauseOnConnect: false, noDelay: true, keepAlive: false, keepAliveInitialDelay: 0, highWaterMark: 16384, httpAllowHalfOpen: false, timeout: 0, maxHeadersCount: null, maxRequestsPerSocket: 0, _connectionKey: '6::::8888', [Symbol(IncomingMessage)]: [Function: IncomingMessage], [Symbol(ServerResponse)]: [Function: ServerResponse], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(async_id_symbol)]: 245, [Symbol(kUniqueHeaders)]: null, [Symbol(http.server.connections)]: ConnectionsList {}, [Symbol(http.server.connectionsCheckingInterval)]: Timeout { _idleTimeout: 30000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 191, _onTimeout: [Function: bound checkConnections], _timerArgs: undefined, _repeat: 30000, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 248, [Symbol(triggerId)]: 246 } }, _server: Server { maxHeaderSize: undefined, insecureHTTPParser: undefined, requestTimeout: 300000, headersTimeout: 60000, keepAliveTimeout: 5000, connectionsCheckingInterval: 30000, requireHostHeader: true, joinDuplicateHeaders: undefined, rejectNonStandardBodyWrites: false, _events: [Object: null prototype], _eventsCount: 3, _maxListeners: undefined, _connections: 1, _handle: [TCP], _usingWorkers: false, _workers: [], _unref: false, _listeningId: 2, allowHalfOpen: true, pauseOnConnect: false, noDelay: true, keepAlive: false, keepAliveInitialDelay: 0, highWaterMark: 16384, httpAllowHalfOpen: false, timeout: 0, maxHeadersCount: null, maxRequestsPerSocket: 0, _connectionKey: '6::::8888', [Symbol(IncomingMessage)]: [Function: IncomingMessage], [Symbol(ServerResponse)]: [Function: ServerResponse], [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(async_id_symbol)]: 245, [Symbol(kUniqueHeaders)]: null, [Symbol(http.server.connections)]: ConnectionsList {}, [Symbol(http.server.connectionsCheckingInterval)]: Timeout { _idleTimeout: 30000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 191, _onTimeout: [Function: bound checkConnections], _timerArgs: undefined, _repeat: 30000, _destroyed: false, [Symbol(refed)]: false, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 248, [Symbol(triggerId)]: 246 } }, parser: HTTPParser { '0': null, '1': [Function: parserOnHeaders], '2': [Function: parserOnHeadersComplete], '3': [Function: parserOnBody], '4': [Function: parserOnMessageComplete], '5': [Function: bound onParserExecute], '6': [Function: bound onParserTimeout], _headers: [], _url: '', socket: [Circular *1], incoming: [Circular *2], outgoing: null, maxHeaderPairs: 2000, _consumed: true, onIncoming: [Function: bound parserOnIncoming], joinDuplicateHeaders: null, [Symbol(resource_symbol)]: [HTTPServerAsyncResource] }, on: [Function: socketListenerWrap], addListener: [Function: socketListenerWrap], prependListener: [Function: socketListenerWrap], setEncoding: [Function: socketSetEncoding], _paused: false, _httpMessage: ServerResponse { _events: [Object: null prototype], _eventsCount: 1, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: false, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: true, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: null, _hasBody: true, _trailer: '', finished: false, _headerSent: false, _closed: false, socket: [Circular *1], _header: null, _keepAliveTimeout: 5000, _onPendingData: [Function: bound updateOutgoingData], req: [Circular *2], _sent100: false, _expect_continue: false, _maxRequestsPerSocket: 0, [Symbol(shapeMode)]: false, [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kHighWaterMark)]: 16384, [Symbol(kRejectNonStandardBodyWrites)]: false, [Symbol(kUniqueHeaders)]: null }, [Symbol(async_id_symbol)]: 250, [Symbol(kHandle)]: TCP { reading: true, onconnection: null, _consumed: true, [Symbol(owner_symbol)]: [Circular *1] }, [Symbol(lastWriteQueueSize)]: 0, [Symbol(timeout)]: null, [Symbol(kBuffer)]: null, [Symbol(kBufferCb)]: null, [Symbol(kBufferGen)]: null, [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kSetNoDelay)]: true, [Symbol(kSetKeepAlive)]: false, [Symbol(kSetKeepAliveInitialDelay)]: 0, [Symbol(kBytesRead)]: 0, [Symbol(kBytesWritten)]: 0 }, _consuming: false, _dumped: false, [Symbol(shapeMode)]: true, [Symbol(kCapture)]: false, [Symbol(kHeaders)]: { host: 'localhost:8888', connection: 'keep-alive', 'content-length': '45', 'sec-ch-ua-platform': '"Windows"', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', accept: 'application/json, text/plain, */*', 'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"', 'content-type': 'application/json', 'x-custom-header': 'foobar', 'sec-ch-ua-mobile': '?0', origin: 'http://localhost:5173', 'sec-fetch-site': 'same-site', 'sec-fetch-mode': 'cors', 'sec-fetch-dest': 'empty', referer: 'http://localhost:5173/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'zh-CN,zh;q=0.9' }, [Symbol(kHeadersCount)]: 34, [Symbol(kTrailers)]: null, [Symbol(kTrailersCount)]: 0 }
原生node.js接收前端数据
//接收数据 let body = ''; // 每次接收到一部分数据,就累加到 body req.on('data', chunk => { body += chunk.toString(); }); // 数据接收完毕后,在这里处理完整的 body req.on('end', () => { //解析JSON格式 try { const data = JSON.parse(body); console.log('接收到的数据:', data); res.end('ok'); } catch (err) { console.error('解析失败:', err); res.statusCode = 400; res.end('Invalid JSON'); } });
req.on
在 Node.js 的 HTTP 服务器处理中,`req.on` 用于监听 HTTP 请求对象 (`IncomingMessage`) 的事件。`req` 是一个继承了 `EventEmitter` 类的对象,可以通过 `.on()` 方法监听各种请求相关的事件。 以下是常见的 `req.on` 使用场景和详细解释: --- ### 1. **接收请求体数据(POST/PUT 等)** 当客户端通过 POST 或 PUT 方法发送数据时,数据会被分成多个 **chunk(数据块)** 传输。你需要监听 `'data'` 和 `'end'` 事件来完整接收数据。 ```javascript const http = require('http'); const server = http.createServer((req, res) => { let body = []; // 监听 'data' 事件:每次接收到数据块时触发 req.on('data', (chunk) => { body.push(chunk); // 将数据块存入数组 }); // 监听 'end' 事件:所有数据接收完成后触发 req.on('end', () => { body = Buffer.concat(body).toString(); // 合并所有数据块 console.log('Received body:', body); res.end('Data received'); }); }); server.listen(3000); ``` - **为什么需要这样处理?** HTTP 请求体可能很大,Node.js 以流(Stream)的形式逐步传输数据,避免内存溢出。 --- ### 2. **处理请求错误** 监听 `'error'` 事件可以捕获请求过程中发生的错误(如客户端提前断开连接)。 ```javascript req.on('error', (err) => { console.error('Request error:', err); // 可以在此处关闭连接或清理资源 }); ``` --- ### 3. **其他事件** - **`'close'`**: 当底层连接关闭时触发。 - **`'aborted'`**: 当请求被客户端中止时触发。 --- ### 4. **注意事项** - **必须监听 `'data'` 才会触发 `'end'`** 如果你不监听 `'data'` 事件,流会处于 **暂停模式**,`'end'` 事件永远不会触发。 - **流(Stream)的工作模式** - **流动模式(Flowing Mode)**: 通过 `.on('data')` 自动接收数据。 - **暂停模式(Paused Mode)**: 需要手动调用 `.read()` 读取数据。 - **框架的封装** 在 Express 或 Koa 等框架中,通常使用中间件(如 `body-parser`)自动处理请求体数据,无需手动监听 `'data'` 和 `'end'`。 --- ### 5. **完整示例** ```javascript const http = require('http'); const server = http.createServer((req, res) => { let data = ''; req.on('data', (chunk) => { data += chunk; // 拼接数据块(字符串形式) }); req.on('end', () => { try { const jsonData = JSON.parse(data); // 解析 JSON 数据 res.end('Data processed'); } catch (err) { res.statusCode = 400; res.end('Invalid JSON'); } }); req.on('error', (err) => { console.error('Request error:', err); res.statusCode = 500; res.end('Internal Server Error'); }); }); server.listen(3000, () => { console.log('Server running on port 3000'); }); ``` --- ### 6. **Express 中的对比** 在 Express 中,使用 `express.json()` 中间件后,可以直接通过 `req.body` 获取解析后的数据,无需手动监听事件: ```javascript const express = require('express'); const app = express(); app.use(express.json()); // 自动处理 JSON 请求体 app.post('/', (req, res) => { console.log(req.body); // 直接访问解析后的数据 res.send('Data received'); }); app.listen(3000); ``` --- ### 总结 - **`req.on`** 用于监听 HTTP 请求对象的事件,适用于原始 Node.js 环境。 - 主要事件:`data`(接收数据块)、`end`(数据接收完成)、`error`(处理错误)。 - 在框架中(如 Express),通常有更简洁的封装,无需直接操作这些事件。
相关文章:
Node.js心得笔记
npm init 可用npm 来调试node项目 浏览器中的顶级对象时window <ref *1> Object [global] { global: [Circular *1], clearImmediate: [Function: clearImmediate], setImmediate: [Function: setImmediate] { [Symbol(nodejs.util.promisify.custom)]: [Getter] }, cl…...
多智能体空域协同中的伦理博弈与系统调停
在多智能体系统(MAS)广泛应用于低空飞行调度、应急响应与城市管理的背景下,AI之间的“协同”不仅是算法效率问题,更是伦理角色之间的权责动态博弈。尤其在高频互动、任务冲突、资源抢占等复杂场景中,智能体不再是“工具…...
面试中系统化地解答系统设计题:通用方法论
目录 一、明确需求(Clarify Requirements) (一)理解业务背景 (二)功能性需求(Functional Requirements) 1. 分析目标 2. 功能需求分类 A. 用户交互类功能 B. 数据处理类功能 C. 管理与运维类功能 D. 外部系统交互类功能 示例场景详解 3. 捕捉隐藏需求的技巧…...
kotlin中 热流 vs 冷流 的本质区别
🔥 冷流(Cold Flow) vs 热流(Hot Flow)区别 特性冷流(Cold Flow)热流(Hot Flow)数据生产时机每次 collect 才开始执行启动时就开始生产、始终运行生命周期与 collect 者…...
机器视觉开发-打开摄像头
以下是使用Python和OpenCV打开摄像头的最简单实现: import cv2# 打开默认摄像头(通常是0) cap cv2.VideoCapture(0)# 检查摄像头是否成功打开 if not cap.isOpened():print("无法打开摄像头")exit()print("摄像头已打开 - 按…...
Rerank详解
疑惑一 我对rag的流程理解是。后端首先建立embedding后的向量数据库,用户提问使用相同的embedding模型进行向量化,使用阈值控制相似度找出前topk个数据。然后rerank,将rerank的结果打包成prompt返回给大模型进行解答。我对于rerank的过程不是…...
深度探索DeepSeek:从架构设计到性能优化的实战指南
深度解码DeepSeek:从架构设计到工业级部署的全链路优化实践 引言:大模型时代的工程挑战 在人工智能技术进入工业化落地阶段的今天,大模型训练与推理的工程化能力已成为衡量企业技术实力的重要标尺。DeepSeek作为当前业界领先的超大规模语言…...
d202551
目录 一、175. 组合两个表 - 力扣(LeetCode) 二、511. 游戏玩法分析 I - 力扣(LeetCode) 三、1204. 最后一个能进入巴士的人 - 力扣(LeetCode) 一、175. 组合两个表 - 力扣(LeetCode…...
(C题|社交媒体平台用户分析问题)2025年第二十二届五一数学建模竞赛(五一杯/五一赛)解题思路|完整代码论文集合
我是Tina表姐,毕业于中国人民大学,对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在,我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…...
计网_PPP协议
2024.10.15:beokayy计算机网络学习笔记 PPP协议 PPP协议的特点PPP协议应满足的需求(了解)PPP协议的组成(PPP协议有三个组成部分) PPP协议的帧格式PPP协议的工作状态 ISP指的是运营商,比如中国联通、中国电信…...
Mem0.ai研究团队开发的全新记忆架构系统“Mem0”正式发布
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
二叉树删除结点详细代码
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h>typedef int data_t; typedef struct _node {data_t data;struct _node* left;struct _node* right; }node_t;int bst_create(node_t**, data_t);//函数声明BST创建 int bst…...
PyTorch线性代数操作详解:点积、矩阵乘法、范数与轴求和
本文通过代码示例详细讲解PyTorch中常用的线性代数操作,包括点积、矩阵乘法、范数计算以及按轴求和等操作,帮助读者掌握张量运算的核心方法。 1. 点积运算 点积(Dot Product)是两个向量对应元素相乘后求和的结果。 实现代码&…...
Java SE(6)——类和对象
1.初始面向对象 1.1 什么是面向对象 Java是一门纯面向对象的编程语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交换来完成一件事情 1.2 面向过程…...
Kubernetes(k8s)的API Server 组件原理与结合生产实战教程
一、API Server 架构深度解析 1. 核心架构设计 二、生产环境安全加固实战 1. 认证(Authentication) 2. 授权(Authorization) 3. 准入控制(Admission Control) 三、性能优化与调参 1. 关键启动参数 四…...
Java面试高频问题(31-33)
三十一、服务网格:东西向流量治理与故障注入 服务网格架构分层 mermaid graph BT subgraph Control Plane APilot --> BEnvoy Sidecar CMixer --> B DCitadel --> B end subgraph Data Plane B --> E服务A B --> F服务B B --> G服务C end 核心能…...
VSCode开发调试Python入门实践(Windows10)
我的Windows10上的python环境是免安装直接解压的Python3.8.x老版本,可参见《Windows下Python3.8环境快速安装部署。 1. 安装VSCode 在Windows 10系统上安装Visual Studio Code(VS Code)是一个简单的过程,以下是详细的安装方法与…...
C++——入门基础(2)
文章目录 一、前言二、C入门2.1 缺省参数2.2 函数重载2.2.1 参数类型不同2.2.1.1 整体参数类型不同2.2.1.2 参数类型顺序不同 2.2.2 参数个数不同2.2.3 避坑注意2.2.3.1无参与有参2.2.3.2 返回值不同 2.3 引用2.3.1 引用的概念2.3.2引用的结构2.3.3 引用的特点2.3.4引用的作用2…...
【MySQL】复合查询与内外连接
目录 一、复合查询 1、基本查询回顾: 2、多表查询: 3、自连接: 4、子查询: 单列子查询 多行子查询: 多列子查询: 在from语句中使用子查询: 5、合并查询: union࿱…...
第3篇:请求参数处理与数据校验
在 Web 开发中,请求参数处理与数据校验是保障系统稳定性的第一道防线。本文将深入探讨 Egg.js 框架中参数处理的完整解决方案,涵盖常规参数获取、高效校验方案、文件流处理等核心功能,并分享企业级项目中的最佳实践。 一、多场景参数获取策略…...
Android JIT编译:adb shell cmd package compile选项
Android JIT编译:adb shell cmd package compile选项 例如: adb shell cmd package compile -m speed -f --full 包名 配置参数指令说明: compile [-r COMPILATION_REASON] [-m COMPILER_FILTER] [-p PRIORITY] [-f] [--primary-dex] …...
排序算法——冒泡排序
一、介绍 「冒泡排序bubblesort」通过连续地比较与交换相邻元素实现排序。这个过程就像气泡从底部升到顶部一样,因此得名冒泡排序。 冒泡过程可以利用元素交换操作来模拟:从数组最左端开始向右遍历,依次比较相邻元素大小,如果“左…...
文献阅读篇#5:5月一区好文阅读,BFA-YOLO,用于建筑信息建模!(上)
期刊简介:《Advanced Engineering Informatics》创刊于2002年,由Elsevier Ltd出版商出版,出版周期Quarterly。该刊已被SCIE数据库收录,在中科院最新升级版分区表中,该刊分区信息为大类学科工程技术1区,2023…...
工行手机银行安全吗?在应用商店下载工商银行安全吗?
现在很多的人都会用手机银行,其中工行的使用几率也是比较高的,但大家在使用的过程中就会比较关心使用工行手机银行是否安全。如果直接在应用商店下载,是否有安全保障? 工行的手机银行会拥有较高的保障,从技术到服务都可…...
python如何word转pdf
在Python中,将Word文档(.docx或.doc)转换为PDF可以通过多种库实现。以下是几种常见的方法及详细步骤: 方法1:使用 python-docx comtypes(仅Windows,需安装Word) 适用于Windows系统…...
在阿里云 Ubuntu 24.04 上部署 RabbitMQ:一篇实战指南
前言 RabbitMQ 是业界常用的开源消息中间件,支持 AMQP 协议,易于部署、高可用、插件丰富。本文以阿里云 ECS 上运行的 Ubuntu 24.04 LTS 为例,手把手带你完成 RabbitMQ 从仓库配置到运行的全流程,并分享在国内环境下常见的坑与对应解决方案。 环境概况 操作系统:Ubuntu …...
Linux Shell 重定向与管道符号(>, >>, |)的实现机制
文章目录 Linux Shell 重定向与管道符号(>, >>, |)的实现机制一、重定向基础:dup2() 的核心作用二、输出重定向的实现原理>(覆盖重定向)>>(追加重定向) 三、| 管道符的实现原…...
GitHub 趋势日报 (2025年04月30日)
本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1hacksider/Deep-Live-Camreal time face swap and one-click video deepfake with only a single image⭐ 1686⭐ 54925Python2Qwe…...
计算机操作系统知识集合
主要来自小林coding 硬件结构 cpu位宽 如果用 32 位 CPU 去加和两个 64 位大小的数字,就需要把这 2 个 64 位的数字分成 2 个低位 32 位数字和 2 个高位 32 位数字来计算,先加个两个低位的 32 位数字,算出进位,然后加和两个高位…...
PostgreSQL数据类型
数据类型 数值类型 整数类型 SMALLINT 小范围整数,取值范围:-32768 ~ 32767 INT(INTEGER) 普通大小整数,取值范围:-2147483648 ~ 2147483647 浮点数类型 REAL 6位十进制数字精度 NUMERIC(m, n) 任意精度…...
在Linux中,KVM和Docker在Linux虚拟化中的区别是什么?
KVM(Kernel-based Virtual Machine)和Docker是Linux环境中两种不同的虚拟化技术,它们在实现原理、资源隔离程度、应用场景等方面存在显著区别: 实现原理与技术层级 KVM:KVM是一种基于硬件辅助虚拟化的全虚拟化技术&a…...
【docker学习笔记】如何删除镜像启动默认命令
一些镜像会在它打镜像时,加入一些默认的启动命令,可以通过docker inspect \<image id\>来查看Entrypoint。如下图,docker run启动时,会默认执行 "python3 -m vllm.entrypoints.openai.api_server" 如果不想执行&…...
c语言 39.0625转为16进制
c语言 39.0625转为16进制 寄存器的4~15对应整数部分 39为整数部分 39 (10进制) 0x27(16进制) 寄存器的0~3对应小数部分 0.0625为小数部分 0.0626 1/16 则0~3位十六进制值应为 0x1 39.06250…...
【阿里云大模型高级工程师ACP习题集】2.8 部署模型
习题集: 以下关于直接调用模型(无需部署)的说法,错误的是?【单选题】 A. 无需部署模型,只需简单调用API B. 按token量计费,无需担心模型部署的资源消耗 C. 可随意调用,没有任何限制 D. 适合业务初期或中小规模场景 使用vLLM部署模型时,若出现端口被占用的情况,以下做…...
【进阶】--函数栈帧的创建和销毁详解
目录 一.函数栈帧的概念 二.理解函数栈帧能让我们解决什么问题 三.相关寄存器和汇编指令知识点补充 四.函数栈帧的创建和销毁 4.1.调用堆栈 4.2.函数栈帧的创建 4.3 函数栈帧的销毁 一.函数栈帧的概念 --在C语言中,函数栈帧是指在函数调用过程中,…...
猫,为什么是猫?
英语单词 cat,意为猫: cat n.猫 根据首字母象形原则,通常我们喜欢将首字母C,解释为猫爪,C的形象,通常可解释为字母K的右侧的中间凹陷部分,K | <,也就是 C 和 < 相通&#…...
数字智慧方案6169丨智慧医院后勤管理解决方案(58页PPT)(文末有下载方式)
资料解读:智慧医院后勤管理解决方案 详细资料请看本解读文章的最后内容。 在当今万物互联的时代,传统医院后勤管理模式逐渐暴露出诸多弊端,已难以适应医院集团化发展的需求。这份智慧医院后勤管理解决方案资料,深入剖析了传统管理…...
经济学和奥地利学派的起源
(一)经济学和奥地利学派的起源: 早期思想: 亚当斯密被认为是现代经济学的鼻祖,但早期的亚里士多德、柏拉图以及中国的《管子》等著作也包含经济学思想,但更偏向财政学。 亚当斯密之前的学者: 坎…...
Linux安全清理删除目录bash脚本
直接写清除目录命令可能会因为一时手抖导致删除重要目录 rm -rf是个危险的命令,我写了bash脚本,放在环境变量目录下可以当系统命令来用 这里是单线程的,如果需要更高的性能,需要加入多线程的支持。 1.实现功能 清理目录的子内容…...
C++/SDL 进阶游戏开发 —— 双人塔防(代号:村庄保卫战 17)
🎁个人主页:工藤新一 🔍系列专栏:C面向对象(类和对象篇) 🌟心中的天空之城,终会照亮我前方的路 🎉欢迎大家点赞👍评论📝收藏⭐文章 文章目录 二…...
Lucene并不是只有倒排索引一种数据结构,支持多种数据结构
Lucene 的核心机制确实以**倒排索引(Inverted Index)**为核心,但它并不是“全部”都依赖倒排索引。Lucene 的索引结构中还包含其他辅助数据结构,用于支持不同的查询场景。以下是详细的解释: 1. 核心机制:倒…...
使用Docker一键安装SigLens:简单快捷的日志分析解决方案
在当今复杂的IT环境中,高效的日志管理和分析变得越来越重要。SigLens作为一款强大的开源日志分析工具,为开发者和运维人员提供了直观、高效的日志处理体验。本文将介绍如何使用Docker快速安装SigLens,让您在几分钟内就能开始进行日志分析。 为什么选择Docker安装SigLens? Do…...
【Linux】线程池和线程补充内容
个人主页~ 线程池 一、线程池简介单例模式线程池简介 二、单例模式线程池的实现1、ThreadPool.hpp2、Task.hpp3、main.cpp 三、其他常见锁读写锁 一、线程池简介 池化技术我们并不陌生,我们在前面的文章中实现过进程池,这里线程池的作用也是先申请资源交…...
vue3内置组件Suspense的使用
Suspense 实验性功能<Suspense> 是一项实验性功能。它不一定会最终成为稳定功能,并且在稳定之前相关 API 也可能会发生变化 <Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异…...
怪物猎人:世界-冰原10000+mod整合包5月最新更新!
700A大全套精美服装 800M大全套精美服装 3月31日更新 新增 新武器 新特效MOD 当前共计5800MOD整合包 好看的发型mod 实用的功能mod 炫酷的武器mod 新服装新特效新武器实用模组美化,等。 1月14日更新 新增皮肤MOD 500 当前共计2000MOD 1月16日更新 新增超…...
题解:洛谷 CF2091E Interesting Ratio
思路推导 我们先对 32 32 32 和 96 96 96 进行二进制拆分。 相同部分(用 α \alpha α 表示): 5 5 5 个 2 2 2。 不同部分(用 β \beta β 表示): 1 1 1 和 3 3 3。 gcd ( 32 , 96 ) \gcd(32,9…...
PETR和位置编码
PETR和位置编码 petr检测网络中有2种类型的位置编码。 正弦编码和petr论文提出的3D Position Embedding。transformer模块输入除了qkv,还有query_pos和key_pos。这里重点记录下query_pos和key_pos的生成 query pos的生成 先定义reference_points, shape为(n_query…...
《社交类应用开发:React Native与Flutter的抉择》
社交类应用以令人目不暇接的速度更新迭代。新功能不断涌现,从更智能的算法推荐到多样化的互动形式,从增强的隐私保护到跨平台的无缝体验,每一次更新都旨在满足用户日益增长且多变的需求。面对如此高频的更新需求,选择合适的跨端框…...
多模态大语言模型arxiv论文略读(五十三)
Red Teaming GPT-4V: Are GPT-4V Safe Against Uni/Multi-Modal Jailbreak Attacks? ➡️ 论文标题:Red Teaming GPT-4V: Are GPT-4V Safe Against Uni/Multi-Modal Jailbreak Attacks? ➡️ 论文作者:Shuo Chen, Zhen Han, Bailan He, Zifeng Ding, …...
POI从入门到上手(三)-轻松完成EasyExcel使用,完成Excel导入导出.
前言: Apache POI 是一个流行的 Java 库,用于处理 Microsoft Office 格式文件,提供丰富 API 来创建、读取和修改 Office 文档。 1.官网:Apache POI™ - the Java API for Microsoft Documents 2.优点:功能强大,可处…...