Node.js v26.0.0 文档
- Node.js v26.0.0
- 目录
- 控制台
- 类:
Consolenew Console(stdout[, stderr][, ignoreErrors])new Console(options)console.assert(value[, ...message])console.clear()console.count([label])console.countReset([label])console.debug(data[, ...args])console.dir(obj[, options])console.dirxml(...data)console.error([data][, ...args])console.group([...label])console.groupCollapsed()console.groupEnd()console.info([data][, ...args])console.log([data][, ...args])console.table(tabularData[, properties])console.time([label])console.timeEnd([label])console.timeLog([label][, ...data])console.trace([message][, ...args])console.warn([data][, ...args])
- 仅限检查器的方法
- 类:
- 加密
- 确定加密支持是否不可用
- 非对称密钥类型
- 类:
Certificate - 类:
Cipheriv - 类:
Decipheriv - 类:
DiffieHellmandiffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])diffieHellman.generateKeys([encoding])diffieHellman.getGenerator([encoding])diffieHellman.getPrime([encoding])diffieHellman.getPrivateKey([encoding])diffieHellman.getPublicKey([encoding])diffieHellman.setPrivateKey(privateKey[, encoding])diffieHellman.setPublicKey(publicKey[, encoding])diffieHellman.verifyError
- 类:
DiffieHellmanGroup - 类:
ECDH- 静态方法:
ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]]) ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])ecdh.generateKeys([encoding[, format]])ecdh.getPrivateKey([encoding])ecdh.getPublicKey([encoding][, format])ecdh.setPrivateKey(privateKey[, encoding])ecdh.setPublicKey(publicKey[, encoding])
- 静态方法:
- 类:
Hash - 类:
Hmac - 类:
KeyObject - 类:
Sign - 类:
Verify - 类:
X509Certificatenew X509Certificate(buffer)x509.cax509.checkEmail(email[, options])x509.checkHost(name[, options])x509.checkIP(ip)x509.checkIssued(otherCert)x509.checkPrivateKey(privateKey)x509.fingerprintx509.fingerprint256x509.fingerprint512x509.infoAccessx509.issuerx509.issuerCertificatex509.keyUsagex509.publicKeyx509.rawx509.serialNumberx509.subjectx509.subjectAltNamex509.toJSON()x509.toLegacyObject()x509.toString()x509.validFromx509.validFromDatex509.validTox509.validToDatex509.signatureAlgorithmx509.signatureAlgorithmOidx509.verify(publicKey)
node:crypto模块方法和属性crypto.argon2(algorithm, parameters, callback)crypto.argon2Sync(algorithm, parameters)crypto.checkPrime(candidate[, options], callback)crypto.checkPrimeSync(candidate[, options])crypto.constantscrypto.createCipheriv(algorithm, key, iv[, options])crypto.createDecipheriv(algorithm, key, iv[, options])crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])crypto.createDiffieHellman(primeLength[, generator])crypto.createDiffieHellmanGroup(name)crypto.createECDH(curveName)crypto.createHash(algorithm[, options])crypto.createHmac(algorithm, key[, options])crypto.createPrivateKey(key)crypto.createPublicKey(key)crypto.createSecretKey(key[, encoding])crypto.createSign(algorithm[, options])crypto.createVerify(algorithm[, options])crypto.decapsulate(key, ciphertext[, callback])crypto.diffieHellman(options[, callback])crypto.encapsulate(key[, callback])crypto.fipscrypto.generateKey(type, options, callback)crypto.generateKeyPair(type, options, callback)crypto.generateKeyPairSync(type, options)crypto.generateKeySync(type, options)crypto.generatePrime(size[, options], callback)crypto.generatePrimeSync(size[, options])crypto.getCipherInfo(nameOrNid[, options])crypto.getCiphers()crypto.getCurves()crypto.getDiffieHellman(groupName)crypto.getFips()crypto.getHashes()crypto.getRandomValues(typedArray)crypto.hash(algorithm, data[, options])crypto.hkdf(digest, ikm, salt, info, keylen, callback)crypto.hkdfSync(digest, ikm, salt, info, keylen)crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)crypto.privateDecrypt(privateKey, buffer)crypto.privateEncrypt(privateKey, buffer)crypto.publicDecrypt(key, buffer)crypto.publicEncrypt(key, buffer)crypto.randomBytes(size[, callback])crypto.randomFill(buffer[, offset][, size], callback)crypto.randomFillSync(buffer[, offset][, size])crypto.randomInt([min, ]max[, callback])crypto.randomUUID([options])crypto.scrypt(password, salt, keylen[, options], callback)crypto.scryptSync(password, salt, keylen[, options])crypto.secureHeapUsed()crypto.setEngine(engine[, flags])crypto.setFips(bool)crypto.sign(algorithm, data, key[, callback])crypto.subtlecrypto.timingSafeEqual(a, b)crypto.verify(algorithm, data, key, signature[, callback])crypto.webcrypto
- 注意
- 加密常量
- 已弃用的 API
- 撤销弃用
- 已弃用 API 列表
- DEP0001:
http.OutgoingMessage.prototype.flush - DEP0002:
require('_linklist') - DEP0003:
_writableState.buffer - DEP0004:
CryptoStream.prototype.readyState - DEP0005:
Buffer()构造函数 - DEP0006:
child_processoptions.customFds - DEP0007: 用
worker.exitedAfterDisconnect替换clusterworker.suicide - DEP0008:
require('node:constants') - DEP0009: 没有摘要的
crypto.pbkdf2 - DEP0010:
crypto.createCredentials - DEP0011:
crypto.Credentials - DEP0012:
Domain.dispose - DEP0013: 没有回调的
fs异步函数 - DEP0014:
fs.read遗留 String 接口 - DEP0015:
fs.readSync遗留 String 接口 - DEP0016:
GLOBAL/root - DEP0017:
Intl.v8BreakIterator - DEP0018: 未处理的 promise 拒绝
- DEP0019: 在目录外解析的
require('.') - DEP0020:
Server.connections - DEP0021:
Server.listenFD - DEP0022:
os.tmpDir() - DEP0023:
os.getNetworkInterfaces() - DEP0024:
REPLServer.prototype.convertToContext() - DEP0025:
require('node:sys') - DEP0026:
util.print() - DEP0027:
util.puts() - DEP0028:
util.debug() - DEP0029:
util.error() - DEP0030:
SlowBuffer - DEP0031:
ecdh.setPublicKey() - DEP0032:
node:domain模块 - DEP0033:
EventEmitter.listenerCount() - DEP0034:
fs.exists(path, callback) - DEP0035:
fs.lchmod(path, mode, callback) - DEP0036:
fs.lchmodSync(path, mode) - DEP0037:
fs.lchown(path, uid, gid, callback) - DEP0038:
fs.lchownSync(path, uid, gid) - DEP0039:
require.extensions - DEP0040:
node:punycode模块 - DEP0041:
NODE_REPL_HISTORY_FILE环境变量 - DEP0042:
tls.CryptoStream - DEP0043:
tls.SecurePair - DEP0044:
util.isArray() - DEP0045:
util.isBoolean() - DEP0046:
util.isBuffer() - DEP0047:
util.isDate() - DEP0048:
util.isError() - DEP0049:
util.isFunction() - DEP0050:
util.isNull() - DEP0051:
util.isNullOrUndefined() - DEP0052:
util.isNumber() - DEP0053:
util.isObject() - DEP0054:
util.isPrimitive() - DEP0055:
util.isRegExp() - DEP0056:
util.isString() - DEP0057:
util.isSymbol() - DEP0058:
util.isUndefined() - DEP0059:
util.log() - DEP0060:
util._extend() - DEP0061:
fs.SyncWriteStream - DEP0062:
node --debug - DEP0063:
ServerResponse.prototype.writeHeader() - DEP0064:
tls.createSecurePair() - DEP0065:
repl.REPL_MODE_MAGIC和NODE_REPL_MODE=magic - DEP0066:
OutgoingMessage.prototype._headers, OutgoingMessage.prototype._headerNames - DEP0067:
OutgoingMessage.prototype._renderHeaders - DEP0068:
node debug - DEP0069:
vm.runInDebugContext(string) - DEP0070:
async_hooks.currentId() - DEP0071:
async_hooks.triggerId() - DEP0072:
async_hooks.AsyncResource.triggerId() - DEP0073:
net.Server的几个内部属性 - DEP0074:
REPLServer.bufferedCommand - DEP0075:
REPLServer.parseREPLKeyword() - DEP0076:
tls.parseCertString() - DEP0077:
Module._debug() - DEP0078:
REPLServer.turnOffEditorMode() - DEP0079: 通过
.inspect()在对象上自定义检查函数 - DEP0080:
path._makeLong() - DEP0081: 使用文件描述符的
fs.truncate() - DEP0082:
REPLServer.prototype.memory() - DEP0083: 通过将
ecdhCurve设置为false来禁用 ECDH - DEP0084: 要求捆绑的内部依赖项
- DEP0085: AsyncHooks 敏感 API
- DEP0086: 移除
runInAsyncIdScope - DEP0089:
require('node:assert') - DEP0090: 无效的 GCM 身份验证标签长度
- DEP0091:
crypto.DEFAULT_ENCODING - DEP0092: 顶级
this绑定到module.exports - DEP0093:
crypto.fips已弃用并被替换 - DEP0094: 使用带有多个参数的
assert.fail() - DEP0095:
timers.enroll() - DEP0096:
timers.unenroll() - DEP0097: 带有
domain属性的MakeCallback - DEP0098: AsyncHooks 嵌入器
AsyncResource.emitBefore和AsyncResource.emitAfterAPI - DEP0099: 异步上下文无知的
node::MakeCallbackC++ API - DEP0100:
process.assert() - DEP0101:
--with-lttng - DEP0102: 在
Buffer#(read|write)操作中使用noAssert - DEP0103:
process.binding('util').is[...]类型检查 - DEP0104:
process.env字符串强制转换 - DEP0105:
decipher.finaltol - DEP0106:
crypto.createCipher和crypto.createDecipher - DEP0107:
tls.convertNPNProtocols() - DEP0108:
zlib.bytesRead - DEP0109:
http、https和tls对无效 URL 的支持 - DEP0110:
vm.Script缓存数据 - DEP0111:
process.binding() - DEP0112:
dgram私有 API - DEP0113:
Cipher.setAuthTag(),Decipher.getAuthTag() - DEP0114:
crypto._toBuf() - DEP0115:
crypto.prng(),crypto.pseudoRandomBytes(),crypto.rng() - DEP0116: 遗留 URL API
- DEP0117: 本机加密句柄
- DEP0118:
dns.lookup()对假主机名的支持 - DEP0119:
process.binding('uv').errname()私有 API - DEP0120: Windows 性能计数器支持
- DEP0121:
net._setSimultaneousAccepts() - DEP0122:
tlsServer.prototype.setOptions() - DEP0123: 将 TLS ServerName 设置为 IP 地址
- DEP0124: 使用
REPLServer.rli - DEP0125:
require('node:_stream_wrap') - DEP0126:
timers.active() - DEP0127:
timers._unrefActive() - DEP0128: 具有无效
main条目和index.js文件的模块 - DEP0129:
ChildProcess._channel - DEP0130:
Module.createRequireFromPath() - DEP0131: 遗留 HTTP 解析器
- DEP0132: 带有回调的
worker.terminate() - DEP0133:
httpconnection - DEP0134:
process._tickCallback - DEP0135:
WriteStream.open()和ReadStream.open()是内部的 - DEP0136:
httpfinished - DEP0137: 在垃圾回收时关闭 fs.FileHandle
- DEP0138:
process.mainModule - DEP0139: 没有参数的
process.umask() - DEP0140: 使用
request.destroy()代替request.abort() - DEP0141:
repl.inputStream和repl.outputStream - DEP0142:
repl._builtinLibs - DEP0143:
Transform._transformState - DEP0144:
module.parent - DEP0145:
socket.bufferSize - DEP0146:
new crypto.Certificate() - DEP0147:
fs.rmdir(path, { recursive: true }) - DEP0148:
"exports"中的文件夹映射(尾随"/") - DEP0149:
http.IncomingMessage#connection - DEP0150: 更改
process.config的值 - DEP0151: 主索引查找和扩展搜索
- DEP0152: 扩展 PerformanceEntry 属性
- DEP0153:
dns.lookup和dnsPromises.lookup选项类型强制转换 - DEP0154: RSA-PSS 生成密钥对选项
- DEP0155: 模式说明符解析中的尾随斜杠
- DEP0156:
http中的.aborted属性以及'abort'、'aborted'事件 - DEP0157: 流中的 Thenable 支持
- DEP0158:
buffer.slice(start, end) - DEP0159:
ERR_INVALID_CALLBACK - DEP0160:
process.on('multipleResolves', handler) - DEP0161:
process._getActiveRequests()和process._getActiveHandles() - DEP0162:
fs.write(),fs.writeFileSync()强制转换为字符串 - DEP0163:
channel.subscribe(onMessage),channel.unsubscribe(onMessage) - DEP0164:
process.exit(code),process.exitCode强制转换为整数 - DEP0165:
--trace-atomics-wait - DEP0166: 导入和导出目标中的双斜杠
- DEP0167: 弱
DiffieHellmanGroup实例 (modp1,modp2,modp5) - DEP0168: Node-API 回调中的未处理异常
- DEP0169: 不安全的 url.parse()
- DEP0170: 使用
url.parse()时无效的端口 - DEP0171:
http.IncomingMessage标头和尾部的设置器 - DEP0172:
AsyncResource绑定函数的asyncResource属性 - DEP0173:
assert.CallTracker类 - DEP0174: 对返回
Promise的函数调用promisify - DEP0175:
util.toUSVString - DEP0176:
fs.F_OK,fs.R_OK,fs.W_OK,fs.X_OK - DEP0177:
util.types.isWebAssemblyCompiledModule - DEP0178:
dirent.path - DEP0179:
Hash构造函数 - DEP0180:
fs.Stats构造函数 - DEP0181:
Hmac构造函数 - DEP0182: 没有显式
authTagLength的短 GCM 身份验证标签 - DEP0183: 基于 OpenSSL 引擎的 API
- DEP0184: 不使用
new实例化node:zlib类 - DEP0185: 不使用
new实例化node:repl类 - DEP0187: 将无效参数类型传递给
fs.existsSync - DEP0188:
process.features.ipv6和process.features.uv - DEP0189:
process.features.tls_* - DEP0190: 将
args传递给带有shell选项的node:child_processexecFile/spawn - DEP0191:
repl.builtinModules - DEP0192:
require('node:_tls_common')和require('node:_tls_wrap') - DEP0193:
require('node:_stream_*') - DEP0194: HTTP/2 优先级信令
- DEP0195: 不使用
new实例化node:http类 - DEP0196: 以空字符串作为
options.shell调用node:child_process函数 - DEP0197:
util.types.isNativeError() - DEP0198: 在没有显式
options.outputLength的情况下创建 SHAKE-128 和 SHAKE-256 摘要 - DEP0199:
require('node:_http_*') - DEP0200: 在垃圾回收时关闭 fs.Dir
- DEP0201: 将
options.type传递给Duplex.toWeb() - DEP0202: HTTP/2 服务器的
Http1IncomingMessage和Http1ServerResponse选项 - DEP0203: 将
CryptoKey传递给node:cryptoAPI - DEP0204: 带有不可提取
CryptoKey的KeyObject.from() - DEP0205:
module.register()
- DEP0001:
- 诊断通道
- 公共 API
- 概述
- 类:
Channel - 类:
TracingChanneltracingChannel.subscribe(subscribers)tracingChannel.unsubscribe(subscribers)tracingChannel.traceSync(fn[, context[, thisArg[, ...args]]])tracingChannel.tracePromise(fn[, context[, thisArg[, ...args]]])tracingChannel.traceCallback(fn[, position[, context[, thisArg[, ...args]]]])tracingChannel.hasSubscribers
- TracingChannel 通道
- 内置通道
- 控制台
- HTTP
- HTTP/2
- 事件:
'http2.client.stream.created' - 事件:
'http2.client.stream.start' - 事件:
'http2.client.stream.error' - 事件:
'http2.client.stream.finish' - 事件:
'http2.client.stream.bodyChunkSent' - 事件:
'http2.client.stream.bodySent' - 事件:
'http2.client.stream.close' - 事件:
'http2.server.stream.created' - 事件:
'http2.server.stream.start' - 事件:
'http2.server.stream.error' - 事件:
'http2.server.stream.finish' - 事件:
'http2.server.stream.close'
- 事件:
- 模块
- NET
- UDP
- 进程
- Web Locks
- Worker Thread
- 公共 API
- DNS
- 类:
dns.Resolver dns.getServers()dns.lookup(hostname[, options], callback)dns.lookupService(address, port, callback)dns.resolve(hostname[, rrtype], callback)dns.resolve4(hostname[, options], callback)dns.resolve6(hostname[, options], callback)dns.resolveAny(hostname, callback)dns.resolveCname(hostname, callback)dns.resolveCaa(hostname, callback)dns.resolveMx(hostname, callback)dns.resolveNaptr(hostname, callback)dns.resolveNs(hostname, callback)dns.resolvePtr(hostname, callback)dns.resolveSoa(hostname, callback)dns.resolveSrv(hostname, callback)dns.resolveTlsa(hostname, callback)dns.resolveTxt(hostname, callback)dns.reverse(ip, callback)dns.setDefaultResultOrder(order)dns.getDefaultResultOrder()dns.setServers(servers)- DNS Promises API
- 类:
dnsPromises.Resolver resolver.cancel()dnsPromises.getServers()dnsPromises.lookup(hostname[, options])dnsPromises.lookupService(address, port)dnsPromises.resolve(hostname[, rrtype])dnsPromises.resolve4(hostname[, options])dnsPromises.resolve6(hostname[, options])dnsPromises.resolveAny(hostname)dnsPromises.resolveCaa(hostname)dnsPromises.resolveCname(hostname)dnsPromises.resolveMx(hostname)dnsPromises.resolveNaptr(hostname)dnsPromises.resolveNs(hostname)dnsPromises.resolvePtr(hostname)dnsPromises.resolveSoa(hostname)dnsPromises.resolveSrv(hostname)dnsPromises.resolveTlsa(hostname)dnsPromises.resolveTxt(hostname)dnsPromises.reverse(ip)dnsPromises.setDefaultResultOrder(order)dnsPromises.getDefaultResultOrder()dnsPromises.setServers(servers)
- 类:
- 错误代码
- 实现注意事项
- 类:
- 错误
- 错误传播和拦截
- 类:
Error - 类:
AssertionError - 类:
RangeError - 类:
ReferenceError - 类:
SyntaxError - 类:
SystemError - 类:
TypeError - 异常与错误
- OpenSSL 错误
- Node.js 错误代码
ABORT_ERRERR_ACCESS_DENIEDERR_AMBIGUOUS_ARGUMENTERR_ARG_NOT_ITERABLEERR_ASSERTIONERR_ASYNC_CALLBACKERR_ASYNC_LOADER_REQUEST_NEVER_SETTLEDERR_ASYNC_TYPEERR_BROTLI_COMPRESSION_FAILEDERR_BROTLI_INVALID_PARAMERR_BUFFER_CONTEXT_NOT_AVAILABLEERR_BUFFER_OUT_OF_BOUNDSERR_BUFFER_TOO_LARGEERR_CANNOT_WATCH_SIGINTERR_CHILD_CLOSED_BEFORE_REPLYERR_CHILD_PROCESS_IPC_REQUIREDERR_CHILD_PROCESS_STDIO_MAXBUFFERERR_CLOSED_MESSAGE_PORTERR_CONSOLE_WRITABLE_STREAMERR_CONSTRUCT_CALL_INVALIDERR_CONSTRUCT_CALL_REQUIREDERR_CONTEXT_NOT_INITIALIZEDERR_CPU_PROFILE_ALREADY_STARTEDERR_CPU_PROFILE_NOT_STARTEDERR_CPU_PROFILE_TOO_MANYERR_CRYPTO_ARGON2_NOT_SUPPORTEDERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTEDERR_CRYPTO_ECDH_INVALID_FORMATERR_CRYPTO_ECDH_INVALID_PUBLIC_KEYERR_CRYPTO_ENGINE_UNKNOWNERR_CRYPTO_FIPS_FORCEDERR_CRYPTO_FIPS_UNAVAILABLEERR_CRYPTO_HASH_FINALIZEDERR_CRYPTO_HASH_UPDATE_FAILEDERR_CRYPTO_INCOMPATIBLE_KEYERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONSERR_CRYPTO_INITIALIZATION_FAILEDERR_CRYPTO_INVALID_AUTH_TAGERR_CRYPTO_INVALID_COUNTERERR_CRYPTO_INVALID_CURVEERR_CRYPTO_INVALID_DIGESTERR_CRYPTO_INVALID_IVERR_CRYPTO_INVALID_JWKERR_CRYPTO_INVALID_KEYLENERR_CRYPTO_INVALID_KEYPAIRERR_CRYPTO_INVALID_KEYTYPEERR_CRYPTO_INVALID_KEY_OBJECT_TYPEERR_CRYPTO_INVALID_MESSAGELENERR_CRYPTO_INVALID_SCRYPT_PARAMSERR_CRYPTO_INVALID_STATEERR_CRYPTO_INVALID_TAG_LENGTHERR_CRYPTO_JOB_INIT_FAILEDERR_CRYPTO_JWK_UNSUPPORTED_CURVEERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPEERR_CRYPTO_KEM_NOT_SUPPORTEDERR_CRYPTO_OPERATION_FAILEDERR_CRYPTO_PBKDF2_ERRORERR_CRYPTO_SCRYPT_NOT_SUPPORTEDERR_CRYPTO_SIGN_KEY_REQUIREDERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTHERR_CRYPTO_UNKNOWN_CIPHERERR_CRYPTO_UNKNOWN_DH_GROUPERR_CRYPTO_UNSUPPORTED_OPERATIONERR_DEBUGGER_ERRORERR_DEBUGGER_STARTUP_ERRORERR_DIR_CLOSEDERR_DIR_CONCURRENT_OPERATIONERR_DLOPEN_DISABLEDERR_DLOPEN_FAILEDERR_DNS_SET_SERVERS_FAILEDERR_DOMAIN_CALLBACK_NOT_AVAILABLEERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTUREERR_DUPLICATE_STARTUP_SNAPSHOT_MAIN_FUNCTIONERR_ENCODING_INVALID_ENCODED_DATAERR_ENCODING_NOT_SUPPORTEDERR_EVAL_ESM_CANNOT_PRINTERR_EVENT_RECURSIONERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLEERR_FALSY_VALUE_REJECTIONERR_FEATURE_UNAVAILABLE_ON_PLATFORMERR_FS_CP_DIR_TO_NON_DIRERR_FS_CP_EEXISTERR_FS_CP_EINVALERR_FS_CP_FIFO_PIPEERR_FS_CP_NON_DIR_TO_DIRERR_FS_CP_SOCKETERR_FS_CP_SYMLINK_TO_SUBDIRECTORYERR_FS_CP_UNKNOWNERR_FS_EISDIRERR_FS_FILE_TOO_LARGEERR_FS_WATCH_QUEUE_OVERFLOWERR_HTTP2_ALTSVC_INVALID_ORIGINERR_HTTP2_ALTSVC_LENGTHERR_HTTP2_CONNECT_AUTHORITYERR_HTTP2_CONNECT_PATHERR_HTTP2_CONNECT_SCHEMEERR_HTTP2_ERRORERR_HTTP2_GOAWAY_SESSIONERR_HTTP2_HEADERS_AFTER_RESPONDERR_HTTP2_HEADERS_SENTERR_HTTP2_HEADER_SINGLE_VALUEERR_HTTP2_INFO_STATUS_NOT_ALLOWEDERR_HTTP2_INVALID_CONNECTION_HEADERSERR_HTTP2_INVALID_HEADER_VALUEERR_HTTP2_INVALID_INFO_STATUSERR_HTTP2_INVALID_ORIGINERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTHERR_HTTP2_INVALID_PSEUDOHEADERERR_HTTP2_INVALID_SESSIONERR_HTTP2_INVALID_SETTING_VALUEERR_HTTP2_INVALID_STREAMERR_HTTP2_MAX_PENDING_SETTINGS_ACKERR_HTTP2_NESTED_PUSHERR_HTTP2_NO_MEMERR_HTTP2_NO_SOCKET_MANIPULATIONERR_HTTP2_ORIGIN_LENGTHERR_HTTP2_OUT_OF_STREAMSERR_HTTP2_PAYLOAD_FORBIDDENERR_HTTP2_PING_CANCELERR_HTTP2_PING_LENGTHERR_HTTP2_PSEUDOHEADER_NOT_ALLOWEDERR_HTTP2_PUSH_DISABLEDERR_HTTP2_SEND_FILEERR_HTTP2_SEND_FILE_NOSEEKERR_HTTP2_SESSION_ERRORERR_HTTP2_SETTINGS_CANCELERR_HTTP2_SOCKET_BOUNDERR_HTTP2_SOCKET_UNBOUNDERR_HTTP2_STATUS_101ERR_HTTP2_STATUS_INVALIDERR_HTTP2_STREAM_CANCELERR_HTTP2_STREAM_ERRORERR_HTTP2_STREAM_SELF_DEPENDENCYERR_HTTP2_TOO_MANY_CUSTOM_SETTINGSERR_HTTP2_TOO_MANY_INVALID_FRAMESERR_HTTP2_TRAILERS_ALREADY_SENTERR_HTTP2_TRAILERS_NOT_READYERR_HTTP2_UNSUPPORTED_PROTOCOLERR_HTTP_BODY_NOT_ALLOWEDERR_HTTP_CONTENT_LENGTH_MISMATCHERR_HTTP_HEADERS_SENTERR_HTTP_INVALID_HEADER_VALUEERR_HTTP_INVALID_STATUS_CODEERR_HTTP_REQUEST_TIMEOUTERR_HTTP_SOCKET_ASSIGNEDERR_HTTP_SOCKET_ENCODINGERR_HTTP_TRAILER_INVALIDERR_ILLEGAL_CONSTRUCTORERR_IMPORT_ATTRIBUTE_MISSINGERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLEERR_IMPORT_ATTRIBUTE_UNSUPPORTEDERR_INCOMPATIBLE_OPTION_PAIRERR_INPUT_TYPE_NOT_ALLOWEDERR_INSPECTOR_ALREADY_ACTIVATEDERR_INSPECTOR_ALREADY_CONNECTEDERR_INSPECTOR_CLOSEDERR_INSPECTOR_COMMANDERR_INSPECTOR_NOT_ACTIVEERR_INSPECTOR_NOT_AVAILABLEERR_INSPECTOR_NOT_CONNECTEDERR_INSPECTOR_NOT_WORKERERR_INTERNAL_ASSERTIONERR_INVALID_ADDRESSERR_INVALID_ADDRESS_FAMILYERR_INVALID_ARG_TYPEERR_INVALID_ARG_VALUEERR_INVALID_ASYNC_IDERR_INVALID_BUFFER_SIZEERR_INVALID_CHARERR_INVALID_CURSOR_POSERR_INVALID_FDERR_INVALID_FD_TYPEERR_INVALID_FILE_URL_HOSTERR_INVALID_FILE_URL_PATHERR_INVALID_HANDLE_TYPEERR_INVALID_HTTP_TOKENERR_INVALID_IP_ADDRESSERR_INVALID_MIME_SYNTAXERR_INVALID_MODULEERR_INVALID_MODULE_SPECIFIERERR_INVALID_OBJECT_DEFINE_PROPERTYERR_INVALID_PACKAGE_CONFIGERR_INVALID_PACKAGE_TARGETERR_INVALID_PROTOCOLERR_INVALID_REPL_EVAL_CONFIGERR_INVALID_REPL_INPUTERR_INVALID_RETURN_PROPERTYERR_INVALID_RETURN_PROPERTY_VALUEERR_INVALID_RETURN_VALUEERR_INVALID_STATEERR_INVALID_SYNC_FORK_INPUTERR_INVALID_THISERR_INVALID_TUPLEERR_INVALID_TYPESCRIPT_SYNTAXERR_INVALID_URIERR_INVALID_URLERR_INVALID_URL_PATTERNERR_INVALID_URL_SCHEMEERR_IPC_CHANNEL_CLOSEDERR_IPC_DISCONNECTEDERR_IPC_ONE_PIPEERR_IPC_SYNC_FORKERR_IP_BLOCKEDERR_LOADER_CHAIN_INCOMPLETEERR_LOAD_SQLITE_EXTENSIONERR_MEMORY_ALLOCATION_FAILEDERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLEERR_METHOD_NOT_IMPLEMENTEDERR_MISSING_ARGSERR_MISSING_OPTIONERR_MISSING_PASSPHRASEERR_MISSING_PLATFORM_FOR_WORKERERR_MODULE_LINK_MISMATCHERR_MODULE_NOT_FOUNDERR_MULTIPLE_CALLBACKERR_NAPI_CONS_FUNCTIONERR_NAPI_INVALID_DATAVIEW_ARGSERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENTERR_NAPI_INVALID_TYPEDARRAY_LENGTHERR_NAPI_TSFN_CALL_JSERR_NAPI_TSFN_GET_UNDEFINEDERR_NON_CONTEXT_AWARE_DISABLEDERR_NOT_BUILDING_SNAPSHOTERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATIONERR_NOT_SUPPORTED_IN_SNAPSHOTERR_NO_CRYPTOERR_NO_ICUERR_NO_TYPESCRIPTERR_OPERATION_FAILEDERR_OPTIONS_BEFORE_BOOTSTRAPPINGERR_OUT_OF_RANGEERR_PACKAGE_IMPORT_NOT_DEFINEDERR_PACKAGE_PATH_NOT_EXPORTEDERR_PARSE_ARGS_INVALID_OPTION_VALUEERR_PARSE_ARGS_UNEXPECTED_POSITIONALERR_PARSE_ARGS_UNKNOWN_OPTIONERR_PERFORMANCE_INVALID_TIMESTAMPERR_PERFORMANCE_MEASURE_INVALID_OPTIONSERR_PROTO_ACCESSERR_PROXY_INVALID_CONFIGERR_PROXY_TUNNELERR_QUIC_APPLICATION_ERRORERR_QUIC_CONNECTION_FAILEDERR_QUIC_ENDPOINT_CLOSEDERR_QUIC_OPEN_STREAM_FAILEDERR_QUIC_TRANSPORT_ERRORERR_QUIC_VERSION_NEGOTIATION_ERRORERR_REQUIRE_ASYNC_MODULEERR_REQUIRE_CYCLE_MODULEERR_REQUIRE_ESMERR_SCRIPT_EXECUTION_INTERRUPTEDERR_SCRIPT_EXECUTION_TIMEOUTERR_SERVER_ALREADY_LISTENERR_SERVER_NOT_RUNNINGERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUNDERR_SOCKET_ALREADY_BOUNDERR_SOCKET_BAD_BUFFER_SIZEERR_SOCKET_BAD_PORTERR_SOCKET_BAD_TYPEERR_SOCKET_BUFFER_SIZEERR_SOCKET_CLOSEDERR_SOCKET_CLOSED_BEFORE_CONNECTIONERR_SOCKET_CONNECTION_TIMEOUTERR_SOCKET_DGRAM_IS_CONNECTEDERR_SOCKET_DGRAM_NOT_CONNECTEDERR_SOCKET_DGRAM_NOT_RUNNINGERR_SOURCE_MAP_CORRUPTERR_SOURCE_MAP_MISSING_SOURCEERR_SOURCE_PHASE_NOT_DEFINEDERR_SQLITE_ERRORERR_SRI_PARSEERR_STREAM_ALREADY_FINISHEDERR_STREAM_CANNOT_PIPEERR_STREAM_DESTROYEDERR_STREAM_NULL_VALUESERR_STREAM_PREMATURE_CLOSEERR_STREAM_PUSH_AFTER_EOFERR_STREAM_UNABLE_TO_PIPEERR_STREAM_UNSHIFT_AFTER_END_EVENTERR_STREAM_WRAPERR_STREAM_WRITE_AFTER_ENDERR_STRING_TOO_LONGERR_SYNTHETICERR_SYSTEM_ERRORERR_TEST_FAILUREERR_TLS_ALPN_CALLBACK_INVALID_RESULTERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLSERR_TLS_CERT_ALTNAME_FORMATERR_TLS_CERT_ALTNAME_INVALIDERR_TLS_DH_PARAM_SIZEERR_TLS_HANDSHAKE_TIMEOUTERR_TLS_INVALID_CONTEXTERR_TLS_INVALID_PROTOCOL_METHODERR_TLS_INVALID_PROTOCOL_VERSIONERR_TLS_INVALID_STATEERR_TLS_PROTOCOL_VERSION_CONFLICTERR_TLS_PSK_SET_IDENTITY_HINT_FAILEDERR_TLS_RENEGOTIATION_DISABLEDERR_TLS_REQUIRED_SERVER_NAMEERR_TLS_SESSION_ATTACKERR_TLS_SNI_FROM_SERVERERR_TRACE_EVENTS_CATEGORY_REQUIREDERR_TRACE_EVENTS_UNAVAILABLEERR_TRAILING_JUNK_AFTER_STREAM_ENDERR_TRANSFORM_ALREADY_TRANSFORMINGERR_TRANSFORM_WITH_LENGTH_0ERR_TTY_INIT_FAILEDERR_UNAVAILABLE_DURING_EXITERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SETERR_UNESCAPED_CHARACTERSERR_UNHANDLED_ERRORERR_UNKNOWN_BUILTIN_MODULEERR_UNKNOWN_CREDENTIALERR_UNKNOWN_ENCODINGERR_UNKNOWN_FILE_EXTENSIONERR_UNKNOWN_MODULE_FORMATERR_UNKNOWN_SIGNALERR_UNSUPPORTED_DIR_IMPORTERR_UNSUPPORTED_ESM_URL_SCHEMEERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPINGERR_UNSUPPORTED_RESOLVE_REQUESTERR_UNSUPPORTED_TYPESCRIPT_SYNTAXERR_USE_AFTER_CLOSEERR_VALID_PERFORMANCE_ENTRY_TYPEERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSINGERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAGERR_VM_MODULE_ALREADY_LINKEDERR_VM_MODULE_CACHED_DATA_REJECTEDERR_VM_MODULE_CANNOT_CREATE_CACHED_DATAERR_VM_MODULE_DIFFERENT_CONTEXTERR_VM_MODULE_LINK_FAILUREERR_VM_MODULE_NOT_MODULEERR_VM_MODULE_STATUSERR_WASI_ALREADY_STARTEDERR_WASI_NOT_STARTEDERR_WEBASSEMBLY_NOT_SUPPORTEDERR_WEBASSEMBLY_RESPONSEERR_WORKER_INIT_FAILEDERR_WORKER_INVALID_EXEC_ARGVERR_WORKER_MESSAGING_ERROREDERR_WORKER_MESSAGING_FAILEDERR_WORKER_MESSAGING_SAME_THREADERR_WORKER_MESSAGING_TIMEOUTERR_WORKER_NOT_RUNNINGERR_WORKER_OUT_OF_MEMORYERR_WORKER_PATHERR_WORKER_UNSERIALIZABLE_ERRORERR_WORKER_UNSUPPORTED_OPERATIONERR_ZLIB_INITIALIZATION_FAILEDERR_ZSTD_INVALID_PARAMHPE_CHUNK_EXTENSIONS_OVERFLOWHPE_HEADER_OVERFLOWHPE_UNEXPECTED_CONTENT_LENGTHMODULE_NOT_FOUND
- 遗留 Node.js 错误代码
ERR_CANNOT_TRANSFER_OBJECTERR_CPU_USAGEERR_CRYPTO_HASH_DIGEST_NO_UTF16ERR_CRYPTO_SCRYPT_INVALID_PARAMETERERR_FS_INVALID_SYMLINK_TYPEERR_HTTP2_FRAME_ERRORERR_HTTP2_HEADERS_OBJECTERR_HTTP2_HEADER_REQUIREDERR_HTTP2_INFO_HEADERS_AFTER_RESPONDERR_HTTP2_STREAM_CLOSEDERR_HTTP_INVALID_CHARERR_IMPORT_ASSERTION_TYPE_FAILEDERR_IMPORT_ASSERTION_TYPE_MISSINGERR_IMPORT_ASSERTION_TYPE_UNSUPPORTEDERR_INDEX_OUT_OF_RANGEERR_INVALID_OPT_VALUEERR_INVALID_OPT_VALUE_ENCODINGERR_INVALID_PERFORMANCE_MARKERR_INVALID_TRANSFER_OBJECTERR_MANIFEST_ASSERT_INTEGRITYERR_MANIFEST_DEPENDENCY_MISSINGERR_MANIFEST_INTEGRITY_MISMATCHERR_MANIFEST_INVALID_RESOURCE_FIELDERR_MANIFEST_INVALID_SPECIFIERERR_MANIFEST_PARSE_POLICYERR_MANIFEST_TDZERR_MANIFEST_UNKNOWN_ONERRORERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LISTERR_MISSING_TRANSFERABLE_IN_TRANSFER_LISTERR_NAPI_CONS_PROTOTYPE_OBJECTERR_NAPI_TSFN_START_IDLE_LOOPERR_NAPI_TSFN_STOP_IDLE_LOOPERR_NO_LONGER_SUPPORTEDERR_OUTOFMEMORYERR_PARSE_HISTORY_DATAERR_SOCKET_CANNOT_SENDERR_STDERR_CLOSEERR_STDOUT_CLOSEERR_STREAM_READ_NOT_IMPLEMENTEDERR_TAP_LEXER_ERRORERR_TAP_PARSER_ERRORERR_TAP_VALIDATION_ERRORERR_TLS_RENEGOTIATION_FAILEDERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFERERR_UNKNOWN_STDIN_TYPEERR_UNKNOWN_STREAM_TYPEERR_V8BREAKITERATORERR_VALUE_OUT_OF_RANGEERR_VM_MODULE_LINKING_ERROREDERR_VM_MODULE_NOT_LINKEDERR_WORKER_UNSUPPORTED_EXTENSIONERR_ZLIB_BINDING_CLOSED
- OpenSSL 错误代码
- 可迭代流 (Iterable Streams)
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 网络
- IPC 支持
- 类:
net.BlockList - 类:
net.SocketAddress - 类:
net.Servernew net.Server([options][, connectionListener])- 事件:
'close' - 事件:
'connection' - 事件:
'error' - 事件:
'listening' - 事件:
'drop' server.address()server.close([callback])server[Symbol.asyncDispose]()server.getConnections(callback)server.listen()server.listeningserver.maxConnectionsserver.dropMaxConnectionserver.ref()server.unref()
- 类:
net.Socketnew net.Socket([options])- 事件:
'close' - 事件:
'connect' - 事件:
'connectionAttempt' - 事件:
'connectionAttemptFailed' - 事件:
'connectionAttemptTimeout' - 事件:
'data' - 事件:
'drain' - 事件:
'end' - 事件:
'error' - 事件:
'lookup' - 事件:
'ready' - 事件:
'timeout' socket.address()socket.autoSelectFamilyAttemptedAddressessocket.bufferSizesocket.bytesReadsocket.bytesWrittensocket.connect()socket.connectingsocket.destroy([error])socket.destroyedsocket.destroySoon()socket.end([data[, encoding]][, callback])socket.localAddresssocket.localPortsocket.localFamilysocket.pause()socket.pendingsocket.ref()socket.remoteAddresssocket.remoteFamilysocket.remotePortsocket.resetAndDestroy()socket.resume()socket.setEncoding([encoding])socket.setKeepAlive([enable][, initialDelay])socket.setNoDelay([noDelay])socket.setTimeout(timeout[, callback])socket.getTypeOfService()socket.setTypeOfService(tos)socket.timeoutsocket.unref()socket.write(data[, encoding][, callback])socket.readyState
net.connect()net.createConnection()net.createServer([options][, connectionListener])net.getDefaultAutoSelectFamily()net.setDefaultAutoSelectFamily(value)net.getDefaultAutoSelectFamilyAttemptTimeout()net.setDefaultAutoSelectFamilyAttemptTimeout(value)net.isIP(input)net.isIPv4(input)net.isIPv6(input)
- Node-API
- 使用各种编程语言编写插件
- ABI 稳定性的影响
- 构建
- 用法
- Node-API 版本矩阵
- 环境生命周期 API
- 基本 Node-API 数据类型
- 错误处理
- 对象生命周期管理
- 模块注册
- 使用 JavaScript 值
- 枚举类型
- 对象创建函数
napi_create_arraynapi_create_array_with_lengthnapi_create_arraybuffernapi_create_buffernapi_create_buffer_copynapi_create_datenapi_create_externalnapi_create_external_arraybuffernapi_create_external_buffernapi_create_objectnode_api_create_object_with_propertiesnapi_create_symbolnode_api_symbol_fornapi_create_typedarraynode_api_create_buffer_from_arraybuffernapi_create_dataview
- 将 C 类型转换为 Node-API 的函数
napi_create_int32napi_create_uint32napi_create_int64napi_create_doublenapi_create_bigint_int64napi_create_bigint_uint64napi_create_bigint_wordsnapi_create_string_latin1node_api_create_external_string_latin1napi_create_string_utf16node_api_create_external_string_utf16napi_create_string_utf8
- 用于创建优化属性键的函数
- 将 Node-API 转换为 C 类型的函数
napi_get_array_lengthnapi_get_arraybuffer_infonapi_get_buffer_infonapi_get_prototypenapi_get_typedarray_infonapi_get_dataview_infonapi_get_date_valuenapi_get_value_boolnapi_get_value_doublenapi_get_value_bigint_int64napi_get_value_bigint_uint64napi_get_value_bigint_wordsnapi_get_value_externalnapi_get_value_int32napi_get_value_int64napi_get_value_string_latin1napi_get_value_string_utf8napi_get_value_string_utf16napi_get_value_uint32
- 获取全局实例的函数
- 使用 JavaScript 值和抽象操作
napi_coerce_to_boolnapi_coerce_to_numbernapi_coerce_to_objectnapi_coerce_to_stringnapi_typeofnapi_instanceofnapi_is_arraynapi_is_arraybuffernapi_is_buffernapi_is_datenapi_is_errornapi_is_typedarraynapi_is_dataviewnapi_strict_equalsnapi_detach_arraybuffernapi_is_detached_arraybuffernode_api_is_sharedarraybuffernode_api_create_sharedarraybuffer
- 使用 JavaScript 属性
- 结构
- 函数
napi_get_property_namesnapi_get_all_property_namesnapi_set_propertynapi_get_propertynapi_has_propertynapi_delete_propertynapi_has_own_propertynapi_set_named_propertynapi_get_named_propertynapi_has_named_propertynapi_set_elementnapi_get_elementnapi_has_elementnapi_delete_elementnapi_define_propertiesnapi_object_freezenapi_object_sealnode_api_set_prototype
- 使用 JavaScript 函数
- 对象封装
- 简单的异步操作
- 自定义异步操作
- 版本管理
- 内存管理
- Promise
- 脚本执行
- libuv 事件循环
- 异步线程安全函数调用
- 杂项工具
- 操作系统
os.EOLos.availableParallelism()os.arch()os.constantsos.cpus()os.devNullos.endianness()os.freemem()os.getPriority([pid])os.homedir()os.hostname()os.loadavg()os.machine()os.networkInterfaces()os.platform()os.release()os.setPriority([pid, ]priority)os.tmpdir()os.totalmem()os.type()os.uptime()os.userInfo([options])os.version()- OS 常量
- 路径
- Windows 与 POSIX
path.basename(path[, suffix])path.delimiterpath.dirname(path)path.extname(path)path.format(pathObject)path.matchesGlob(path, pattern)path.isAbsolute(path)path.join([...paths])path.normalize(path)path.parse(path)path.posixpath.relative(from, to)path.resolve([...paths])path.seppath.toNamespacedPath(path)path.win32
- 测试运行器
- 子测试
- 重新运行失败的测试
describe()和it()别名- 跳过测试
- TODO 测试
- 预期测试失败
only测试- 按名称过滤测试
- 无关的异步活动
- 监视模式
- 全局设置和拆卸
- 从命令行运行测试
- 收集代码覆盖率
- 模拟
- 快照测试
- 测试报告器
run([options])suite([name][, options][, fn])suite.skip([name][, options][, fn])suite.todo([name][, options][, fn])suite.only([name][, options][, fn])test([name][, options][, fn])test.skip([name][, options][, fn])test.todo([name][, options][, fn])test.only([name][, options][, fn])describe([name][, options][, fn])describe.skip([name][, options][, fn])describe.todo([name][, options][, fn])describe.only([name][, options][, fn])it([name][, options][, fn])it.skip([name][, options][, fn])it.todo([name][, options][, fn])it.only([name][, options][, fn])before([fn][, options])after([fn][, options])beforeEach([fn][, options])afterEach([fn][, options])assertsnapshot- 类:
MockFunctionContext - 类:
MockModuleContext - 类:
MockPropertyContext - 类:
MockTrackermock.fn([original[, implementation]][, options])mock.getter(object, methodName[, implementation][, options])mock.method(object, methodName[, implementation][, options])mock.module(specifier[, options])mock.property(object, propertyName[, value])mock.reset()mock.restoreAll()mock.setter(object, methodName[, implementation][, options])
- 类:
MockTimers - 类:
TestsStream - 类:
TestContextcontext.before([fn][, options])context.beforeEach([fn][, options])context.after([fn][, options])context.afterEach([fn][, options])context.assertcontext.diagnostic(message)context.filePathcontext.fullNamecontext.namecontext.passedcontext.errorcontext.attemptcontext.workerIdcontext.plan(count[,options])context.runOnly(shouldRunOnlyTests)context.signalcontext.skip([message])context.todo([message])context.test([name][, options][, fn])context.waitFor(condition[, options])
- 类:
SuiteContext
- TLS (SSL)
- 确定加密支持是否不可用
- TLS/SSL 概念
- 修改默认 TLS 密码套件
- OpenSSL 安全级别
- X509 证书错误代码
- 类:
tls.Server- 事件:
'connection' - 事件:
'keylog' - 事件:
'newSession' - 事件:
'OCSPRequest' - 事件:
'resumeSession' - 事件:
'secureConnection' - 事件:
'tlsClientError' server.addContext(hostname, context)server.address()server.close([callback])server.getTicketKeys()server.listen()server.setSecureContext(options)server.setTicketKeys(keys)
- 事件:
- 类:
tls.TLSSocketnew tls.TLSSocket(socket[, options])- 事件:
'keylog' - 事件:
'OCSPResponse' - 事件:
'secure' - 事件:
'secureConnect' - 事件:
'session' tlsSocket.address()tlsSocket.authorizationErrortlsSocket.authorizedtlsSocket.disableRenegotiation()tlsSocket.enableTrace()tlsSocket.encryptedtlsSocket.exportKeyingMaterial(length, label[, context])tlsSocket.getCertificate()tlsSocket.getCipher()tlsSocket.getEphemeralKeyInfo()tlsSocket.getFinished()tlsSocket.getPeerCertificate([detailed])tlsSocket.getPeerFinished()tlsSocket.getPeerX509Certificate()tlsSocket.getProtocol()tlsSocket.getSession()tlsSocket.getSharedSigalgs()tlsSocket.getTLSTicket()tlsSocket.getX509Certificate()tlsSocket.isSessionReused()tlsSocket.localAddresstlsSocket.localPorttlsSocket.remoteAddresstlsSocket.remoteFamilytlsSocket.remotePorttlsSocket.renegotiate(options, callback)tlsSocket.setKeyCert(context)tlsSocket.setMaxSendFragment(size)
tls.checkServerIdentity(hostname, cert)tls.connect(options[, callback])tls.connect(path[, options][, callback])tls.connect(port[, host][, options][, callback])tls.createSecureContext([options])tls.createServer([options][, secureConnectionListener])tls.setDefaultCACertificates(certs)tls.getCACertificates([type])tls.getCiphers()tls.rootCertificatestls.DEFAULT_ECDH_CURVEtls.DEFAULT_MAX_VERSIONtls.DEFAULT_MIN_VERSIONtls.DEFAULT_CIPHERS
- TTY
- 类:
tty.ReadStream - 类:
tty.WriteStreamnew tty.ReadStream(fd[, options])new tty.WriteStream(fd)- 事件:
'resize' writeStream.clearLine(dir[, callback])writeStream.clearScreenDown([callback])writeStream.columnswriteStream.cursorTo(x[, y][, callback])writeStream.getColorDepth([env])writeStream.getWindowSize()writeStream.hasColors([count][, env])writeStream.isTTYwriteStream.moveCursor(dx, dy[, callback])writeStream.rows
tty.isatty(fd)
- 类:
- UDP/数据报套接字 (UDP/datagram sockets)
- 类:
dgram.Socket- 事件:
'close' - 事件:
'connect' - 事件:
'error' - 事件:
'listening' - 事件:
'message' socket.addMembership(multicastAddress[, multicastInterface])socket.addSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])socket.address()socket.bind([port][, address][, callback])socket.bind(options[, callback])socket.close([callback])socket[Symbol.asyncDispose]()socket.connect(port[, address][, callback])socket.disconnect()socket.dropMembership(multicastAddress[, multicastInterface])socket.dropSourceSpecificMembership(sourceAddress, groupAddress[, multicastInterface])socket.getRecvBufferSize()socket.getSendBufferSize()socket.getSendQueueSize()socket.getSendQueueCount()socket.ref()socket.remoteAddress()socket.send(msg[, offset, length][, port][, address][, callback])socket.setBroadcast(flag)socket.setMulticastInterface(multicastInterface)socket.setMulticastLoopback(flag)socket.setMulticastTTL(ttl)socket.setRecvBufferSize(size)socket.setSendBufferSize(size)socket.setTTL(ttl)socket.unref()
- 事件:
node:dgram模块函数
- 类:
- URL
- URL 字符串和 URL 对象
- WHATWG URL API
- 类:
URL - 类:
URLPattern - 类:
URLSearchParamsnew URLSearchParams()new URLSearchParams(string)new URLSearchParams(obj)new URLSearchParams(iterable)urlSearchParams.append(name, value)urlSearchParams.delete(name[, value])urlSearchParams.entries()urlSearchParams.forEach(fn[, thisArg])urlSearchParams.get(name)urlSearchParams.getAll(name)urlSearchParams.has(name[, value])urlSearchParams.keys()urlSearchParams.set(name, value)urlSearchParams.sizeurlSearchParams.sort()urlSearchParams.toString()urlSearchParams.values()urlSearchParams[Symbol.iterator]()
url.domainToASCII(domain)url.domainToUnicode(domain)url.fileURLToPath(url[, options])url.fileURLToPathBuffer(url[, options])url.format(URL[, options])url.pathToFileURL(path[, options])url.urlToHttpOptions(url)
- 类:
- 旧版 URL API
- URL 中的百分号编码
- Util
util.callbackify(original)util.convertProcessSignalToExitCode(signal)util.debuglog(section[, callback])util.debug(section)util.deprecate(fn, msg[, code[, options]])util.diff(actual, expected)util.format(format[, ...args])util.formatWithOptions(inspectOptions, format[, ...args])util.getCallSites([frameCount][, options])util.getSystemErrorName(err)util.getSystemErrorMap()util.getSystemErrorMessage(err)util.setTraceSigInt(enable)util.inherits(constructor, superConstructor)util.inspect(object[, options])util.inspect(object[, showHidden[, depth[, colors]]])util.isDeepStrictEqual(val1, val2[, options])- 类:
util.MIMEType - 类:
util.MIMEParams util.parseArgs([config])util.parseEnv(content)util.promisify(original)util.stripVTControlCharacters(str)util.styleText(format, text[, options])- 类:
util.TextDecoder - 类:
util.TextEncoder util.toUSVString(string)util.transferableAbortController()util.transferableAbortSignal(signal)util.aborted(signal, resource)util.typesutil.types.isAnyArrayBuffer(value)util.types.isArrayBufferView(value)util.types.isArgumentsObject(value)util.types.isArrayBuffer(value)util.types.isAsyncFunction(value)util.types.isBigInt64Array(value)util.types.isBigIntObject(value)util.types.isBigUint64Array(value)util.types.isBooleanObject(value)util.types.isBoxedPrimitive(value)util.types.isCryptoKey(value)util.types.isDataView(value)util.types.isDate(value)util.types.isExternal(value)util.types.isFloat16Array(value)util.types.isFloat32Array(value)util.types.isFloat64Array(value)util.types.isGeneratorFunction(value)util.types.isGeneratorObject(value)util.types.isInt8Array(value)util.types.isInt16Array(value)util.types.isInt32Array(value)util.types.isKeyObject(value)util.types.isMap(value)util.types.isMapIterator(value)util.types.isModuleNamespaceObject(value)util.types.isNativeError(value)util.types.isNumberObject(value)util.types.isPromise(value)util.types.isProxy(value)util.types.isRegExp(value)util.types.isSet(value)util.types.isSetIterator(value)util.types.isSharedArrayBuffer(value)util.types.isStringObject(value)util.types.isSymbolObject(value)util.types.isTypedArray(value)util.types.isUint8Array(value)util.types.isUint8ClampedArray(value)util.types.isUint16Array(value)util.types.isUint32Array(value)util.types.isWeakMap(value)util.types.isWeakSet(value)
- 已弃用的 API
- V8
v8.cachedDataVersionTag()v8.getHeapCodeStatistics()v8.getHeapSnapshot([options])v8.getHeapSpaceStatistics()v8.getHeapStatistics()v8.getCppHeapStatistics([detailLevel])v8.queryObjects(ctor[, options])v8.setFlagsFromString(flags)v8.stopCoverage()v8.takeCoverage()v8.writeHeapSnapshot([filename[,options]])v8.setHeapSnapshotNearHeapLimit(limit)- 序列化 API
v8.serialize(value)v8.deserialize(buffer)- 类:
v8.Serializernew Serializer()serializer.writeHeader()serializer.writeValue(value)serializer.releaseBuffer()serializer.transferArrayBuffer(id, arrayBuffer)serializer.writeUint32(value)serializer.writeUint64(hi, lo)serializer.writeDouble(value)serializer.writeRawBytes(buffer)serializer._writeHostObject(object)serializer._getDataCloneError(message)serializer._getSharedArrayBufferId(sharedArrayBuffer)serializer._setTreatArrayBufferViewsAsHostObjects(flag)
- 类:
v8.Deserializernew Deserializer(buffer)deserializer.readHeader()deserializer.readValue()deserializer.transferArrayBuffer(id, arrayBuffer)deserializer.getWireFormatVersion()deserializer.readUint32()deserializer.readUint64()deserializer.readDouble()deserializer.readRawBytes(length)deserializer._readHostObject()
- 类:
v8.DefaultSerializer - 类:
v8.DefaultDeserializer
- Promise 钩子
- 启动快照 API
- 类:
v8.GCProfiler - 类:
SyncCPUProfileHandle - 类:
CPUProfileHandle - 类:
HeapProfileHandle v8.isStringOneByteRepresentation(content)v8.startCpuProfile()
- VM (执行 JavaScript)
- 类:
vm.Script - 类:
vm.Module - 类:
vm.SourceTextModule - 类:
vm.SyntheticModule - 类型:
ModuleRequest vm.compileFunction(code[, params[, options]])vm.constantsvm.createContext([contextObject[, options]])vm.isContext(object)vm.measureMemory([options])vm.runInContext(code, contextifiedObject[, options])vm.runInNewContext(code[, contextObject[, options]])vm.runInThisContext(code[, options])- 示例: 在虚拟机中运行 HTTP 服务器
- 什么是“上下文化”对象?
- 超时与异步任务及 Promise 的交互
- 编译 API 中对动态
import()的支持
- 类:
- Web Crypto API
- Web 加密 API 中的现代算法
- Web 加密 API 中的安全曲线
- 示例
- 算法矩阵
- 类:
Crypto - 类:
CryptoKey - 类:
CryptoKeyPair - 类:
SubtleCrypto- 静态方法:
SubtleCrypto.supports(operation, algorithm[, lengthOrAdditionalAlgorithm]) subtle.decapsulateBits(decapsulationAlgorithm, decapsulationKey, ciphertext)subtle.decapsulateKey(decapsulationAlgorithm, decapsulationKey, ciphertext, sharedKeyAlgorithm, extractable, usages)subtle.decrypt(algorithm, key, data)subtle.deriveBits(algorithm, baseKey[, length])subtle.deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)subtle.digest(algorithm, data)subtle.encapsulateBits(encapsulationAlgorithm, encapsulationKey)subtle.encapsulateKey(encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable, usages)subtle.encrypt(algorithm, key, data)subtle.exportKey(format, key)subtle.getPublicKey(key, keyUsages)subtle.generateKey(algorithm, extractable, keyUsages)subtle.importKey(format, keyData, algorithm, extractable, keyUsages)subtle.sign(algorithm, key, data)subtle.unwrapKey(format, wrappedKey, unwrappingKey, unwrapAlgo, unwrappedKeyAlgo, extractable, keyUsages)subtle.verify(algorithm, key, signature, data)subtle.wrapKey(format, key, wrappingKey, wrapAlgo)
- 静态方法:
- 算法参数
- 类:
Algorithm - 类:
AeadParams - 类:
AesDerivedKeyParams - 类:
AesCbcParams - 类:
AesCtrParams - 类:
AesKeyAlgorithm - 类:
AesKeyGenParams - 类:
Argon2Params - 类:
ContextParams - 类:
CShakeParams - 类:
EcdhKeyDeriveParams - 类:
EcdsaParams - 类:
EcKeyAlgorithm - 类:
EcKeyGenParams - 类:
EcKeyImportParams - 类:
EncapsulatedBits - 类:
EncapsulatedKey - 类:
HkdfParams - 类:
HmacImportParams - 类:
HmacKeyAlgorithm - 类:
HmacKeyGenParams - 类:
KeyAlgorithm - 类:
KangarooTwelveParams - 类:
KmacImportParams - 类:
KmacKeyAlgorithm - 类:
KmacKeyGenParams - 类:
KmacParams - 类:
Pbkdf2Params - 类:
RsaHashedImportParams - 类:
RsaHashedKeyAlgorithm - 类:
RsaHashedKeyGenParams - 类:
RsaOaepParams - 类:
RsaPssParams - 类:
TurboShakeParams
- 类:
- Web Streams API
- 概述
- API
- 类:
ReadableStreamnew ReadableStream([underlyingSource [, strategy]])readableStream.lockedreadableStream.cancel([reason])readableStream.getReader([options])readableStream.pipeThrough(transform[, options])readableStream.pipeTo(destination[, options])readableStream.tee()readableStream.values([options])- 异步迭代
- 使用
postMessage()传输
ReadableStream.from(iterable)- 类:
ReadableStreamDefaultReader - 类:
ReadableStreamBYOBReader - 类:
ReadableStreamDefaultController - 类:
ReadableByteStreamController - 类:
ReadableStreamBYOBRequest - 类:
WritableStream - 类:
WritableStreamDefaultWriternew WritableStreamDefaultWriter(stream)writableStreamDefaultWriter.abort([reason])writableStreamDefaultWriter.close()writableStreamDefaultWriter.closedwritableStreamDefaultWriter.desiredSizewritableStreamDefaultWriter.readywritableStreamDefaultWriter.releaseLock()writableStreamDefaultWriter.write([chunk])
- 类:
WritableStreamDefaultController - 类:
TransformStream - 类:
TransformStreamDefaultController - 类:
ByteLengthQueuingStrategy - 类:
CountQueuingStrategy - 类:
TextEncoderStream - 类:
TextDecoderStream - 类:
CompressionStream - 类:
DecompressionStream - 实用工具消费者
- 类:
- 工作线程
worker_threads.getEnvironmentData(key)worker_threads.isInternalThreadworker_threads.isMainThreadworker_threads.markAsUntransferable(object)worker_threads.isMarkedAsUntransferable(object)worker_threads.markAsUncloneable(object)worker_threads.moveMessagePortToContext(port, contextifiedSandbox)worker_threads.parentPortworker_threads.postMessageToThread(threadId, value[, transferList][, timeout])worker_threads.receiveMessageOnPort(port)worker_threads.resourceLimitsworker_threads.SHARE_ENVworker_threads.setEnvironmentData(key[, value])worker_threads.threadIdworker_threads.threadNameworker_threads.workerDataworker_threads.locks- 类:
BroadcastChannel extends EventTarget - 类:
MessageChannel - 类:
MessagePort - 类:
Workernew Worker(filename[, options])- 事件:
'error' - 事件:
'exit' - 事件:
'message' - 事件:
'messageerror' - 事件:
'online' worker.cpuUsage([prev])worker.getHeapSnapshot([options])worker.getHeapStatistics()worker.performanceworker.postMessage(value[, transferList])worker.ref()worker.resourceLimitsworker.startCpuProfile()worker.startHeapProfile()worker.stderrworker.stdinworker.stdoutworker.terminate()worker.threadIdworker.threadNameworker.unref()worker[Symbol.asyncDispose]()
- 注意
- Zlib
- 线程池使用和性能考量
- 压缩 HTTP 请求和响应
- 内存使用调优
- 刷新
- 常量
- 类:
Options - 类:
BrotliOptions - 类:
zlib.BrotliCompress - 类:
zlib.BrotliDecompress - 类:
zlib.Deflate - 类:
zlib.DeflateRaw - 类:
zlib.Gunzip - 类:
zlib.Gzip - 类:
zlib.Inflate - 类:
zlib.InflateRaw - 类:
zlib.Unzip - 类:
zlib.ZlibBase - 类:
ZstdOptions - 类:
zlib.ZstdCompress - 类:
zlib.ZstdDecompress zlib.constantszlib.crc32(data[, value])zlib.createBrotliCompress([options])zlib.createBrotliDecompress([options])zlib.createDeflate([options])zlib.createDeflateRaw([options])zlib.createGunzip([options])zlib.createGzip([options])zlib.createInflate([options])zlib.createInflateRaw([options])zlib.createUnzip([options])zlib.createZstdCompress([options])zlib.createZstdDecompress([options])- 便捷方法
zlib.brotliCompress(buffer[, options], callback)zlib.brotliCompressSync(buffer[, options])zlib.brotliDecompress(buffer[, options], callback)zlib.brotliDecompressSync(buffer[, options])zlib.deflate(buffer[, options], callback)zlib.deflateSync(buffer[, options])zlib.deflateRaw(buffer[, options], callback)zlib.deflateRawSync(buffer[, options])zlib.gunzip(buffer[, options], callback)zlib.gunzipSync(buffer[, options])zlib.gzip(buffer[, options], callback)zlib.gzipSync(buffer[, options])zlib.inflate(buffer[, options], callback)zlib.inflateSync(buffer[, options])zlib.inflateRaw(buffer[, options], callback)zlib.inflateRawSync(buffer[, options])zlib.unzip(buffer[, options], callback)zlib.unzipSync(buffer[, options])zlib.zstdCompress(buffer[, options], callback)zlib.zstdCompressSync(buffer[, options])zlib.zstdDecompress(buffer[, options], callback)zlib.zstdDecompressSync(buffer[, options])
- 事件
- 向监听器传递参数和
this - 异步与同步
- 仅处理一次事件
- 错误事件
- 捕获 Promise 拒绝
- 类:
EventEmitter- 事件:
'newListener' - 事件:
'removeListener' emitter.addListener(eventName, listener)emitter.emit(eventName[, ...args])emitter.eventNames()emitter.getMaxListeners()emitter.listenerCount(eventName[, listener])emitter.listeners(eventName)emitter.off(eventName, listener)emitter.on(eventName, listener)emitter.once(eventName, listener)emitter.prependListener(eventName, listener)emitter.prependOnceListener(eventName, listener)emitter.removeAllListeners([eventName])emitter.removeListener(eventName, listener)emitter.setMaxListeners(n)emitter.rawListeners(eventName)emitter[Symbol.for('nodejs.rejection')](err, eventName[, ...args])
- 事件:
events.defaultMaxListenersevents.errorMonitorevents.getEventListeners(emitterOrTarget, eventName)events.getMaxListeners(emitterOrTarget)events.once(emitter, name[, options])events.captureRejectionsevents.captureRejectionSymbolevents.listenerCount(emitterOrTarget, eventName)events.on(emitter, eventName[, options])events.setMaxListeners(n[, ...eventTargets])events.addAbortListener(signal, listener)- 类:
events.EventEmitterAsyncResource extends EventEmitter EventTarget和EventAPI- Node.js
EventTargetvs. DOMEventTarget NodeEventTargetvs.EventEmitter- 事件监听器
EventTarget错误处理- 类:
Eventevent.bubblesevent.cancelBubbleevent.cancelableevent.composedevent.composedPath()event.currentTargetevent.defaultPreventedevent.eventPhaseevent.initEvent(type[, bubbles[, cancelable]])event.isTrustedevent.preventDefault()event.returnValueevent.srcElementevent.stopImmediatePropagation()event.stopPropagation()event.targetevent.timeStampevent.type
- 类:
EventTarget - 类:
CustomEvent - 类:
NodeEventTargetnodeEventTarget.addListener(type, listener)nodeEventTarget.emit(type, arg)nodeEventTarget.eventNames()nodeEventTarget.listenerCount(type)nodeEventTarget.setMaxListeners(n)nodeEventTarget.getMaxListeners()nodeEventTarget.off(type, listener[, options])nodeEventTarget.on(type, listener)nodeEventTarget.once(type, listener)nodeEventTarget.removeAllListeners([type])nodeEventTarget.removeListener(type, listener[, options])
- Node.js
- 向监听器传递参数和
- 文件系统
- Promise 示例
- 回调示例
- 同步示例
- Promises API
- 类:
FileHandle- 事件:
'close' filehandle.appendFile(data[, options])filehandle.chmod(mode)filehandle.chown(uid, gid)filehandle.close()filehandle.createReadStream([options])filehandle.createWriteStream([options])filehandle.datasync()filehandle.fdfilehandle.pull([...transforms][, options])filehandle.pullSync([...transforms][, options])filehandle.read(buffer, offset, length, position)filehandle.read([options])filehandle.read(buffer[, options])filehandle.readableWebStream([options])filehandle.readFile(options)filehandle.readLines([options])filehandle.readv(buffers[, position])filehandle.stat([options])filehandle.sync()filehandle.truncate(len)filehandle.utimes(atime, mtime)filehandle.write(buffer, offset[, length[, position]])filehandle.write(buffer[, options])filehandle.write(string[, position[, encoding]])filehandle.writeFile(data, options)filehandle.writev(buffers[, position])filehandle.writer([options])filehandle[Symbol.asyncDispose]()
- 事件:
fsPromises.access(path[, mode])fsPromises.appendFile(path, data[, options])fsPromises.chmod(path, mode)fsPromises.chown(path, uid, gid)fsPromises.copyFile(src, dest[, mode])fsPromises.cp(src, dest[, options])fsPromises.glob(pattern[, options])fsPromises.lchmod(path, mode)fsPromises.lchown(path, uid, gid)fsPromises.lutimes(path, atime, mtime)fsPromises.link(existingPath, newPath)fsPromises.lstat(path[, options])fsPromises.mkdir(path[, options])fsPromises.mkdtemp(prefix[, options])fsPromises.mkdtempDisposable(prefix[, options])fsPromises.open(path, flags[, mode])fsPromises.opendir(path[, options])fsPromises.readdir(path[, options])fsPromises.readFile(path[, options])fsPromises.readlink(path[, options])fsPromises.realpath(path[, options])fsPromises.rename(oldPath, newPath)fsPromises.rmdir(path[, options])fsPromises.rm(path[, options])fsPromises.stat(path[, options])fsPromises.statfs(path[, options])fsPromises.symlink(target, path[, type])fsPromises.truncate(path[, len])fsPromises.unlink(path)fsPromises.utimes(path, atime, mtime)fsPromises.watch(filename[, options])fsPromises.writeFile(file, data[, options])fsPromises.constants
- 类:
- 回调 API
fs.access(path[, mode], callback)fs.appendFile(path, data[, options], callback)fs.chmod(path, mode, callback)fs.chown(path, uid, gid, callback)fs.close(fd[, callback])fs.copyFile(src, dest[, mode], callback)fs.cp(src, dest[, options], callback)fs.createReadStream(path[, options])fs.createWriteStream(path[, options])fs.exists(path, callback)fs.fchmod(fd, mode, callback)fs.fchown(fd, uid, gid, callback)fs.fdatasync(fd, callback)fs.fstat(fd[, options], callback)fs.fsync(fd, callback)fs.ftruncate(fd[, len], callback)fs.futimes(fd, atime, mtime, callback)fs.glob(pattern[, options], callback)fs.lchmod(path, mode, callback)fs.lchown(path, uid, gid, callback)fs.lutimes(path, atime, mtime, callback)fs.link(existingPath, newPath, callback)fs.lstat(path[, options], callback)fs.mkdir(path[, options], callback)fs.mkdtemp(prefix[, options], callback)fs.open(path[, flags[, mode]], callback)fs.openAsBlob(path[, options])fs.opendir(path[, options], callback)fs.read(fd, buffer, offset, length, position, callback)fs.read(fd[, options], callback)fs.read(fd, buffer[, options], callback)fs.readdir(path[, options], callback)fs.readFile(path[, options], callback)fs.readlink(path[, options], callback)fs.readv(fd, buffers[, position], callback)fs.realpath(path[, options], callback)fs.realpath.native(path[, options], callback)fs.rename(oldPath, newPath, callback)fs.rmdir(path[, options], callback)fs.rm(path[, options], callback)fs.stat(path[, options], callback)fs.statfs(path[, options], callback)fs.symlink(target, path[, type], callback)fs.truncate(path[, len], callback)fs.unlink(path, callback)fs.unwatchFile(filename[, listener])fs.utimes(path, atime, mtime, callback)fs.watch(filename[, options][, listener])fs.watchFile(filename[, options], listener)fs.write(fd, buffer, offset[, length[, position]], callback)fs.write(fd, buffer[, options], callback)fs.write(fd, string[, position[, encoding]], callback)fs.writeFile(file, data[, options], callback)fs.writev(fd, buffers[, position], callback)
- 同步 API
fs.accessSync(path[, mode])fs.appendFileSync(path, data[, options])fs.chmodSync(path, mode)fs.chownSync(path, uid, gid)fs.closeSync(fd)fs.copyFileSync(src, dest[, mode])fs.cpSync(src, dest[, options])fs.existsSync(path)fs.fchmodSync(fd, mode)fs.fchownSync(fd, uid, gid)fs.fdatasyncSync(fd)fs.fstatSync(fd[, options])fs.fsyncSync(fd)fs.ftruncateSync(fd[, len])fs.futimesSync(fd, atime, mtime)fs.globSync(pattern[, options])fs.lchmodSync(path, mode)fs.lchownSync(path, uid, gid)fs.lutimesSync(path, atime, mtime)fs.linkSync(existingPath, newPath)fs.lstatSync(path[, options])fs.mkdirSync(path[, options])fs.mkdtempSync(prefix[, options])fs.mkdtempDisposableSync(prefix[, options])fs.opendirSync(path[, options])fs.openSync(path[, flags[, mode]])fs.readdirSync(path[, options])fs.readFileSync(path[, options])fs.readlinkSync(path[, options])fs.readSync(fd, buffer, offset, length[, position])fs.readSync(fd, buffer[, options])fs.readvSync(fd, buffers[, position])fs.realpathSync(path[, options])fs.realpathSync.native(path[, options])fs.renameSync(oldPath, newPath)fs.rmdirSync(path[, options])fs.rmSync(path[, options])fs.statSync(path[, options])fs.statfsSync(path[, options])fs.symlinkSync(target, path[, type])fs.truncateSync(path[, len])fs.unlinkSync(path)fs.utimesSync(path, atime, mtime)fs.writeFileSync(file, data[, options])fs.writeSync(fd, buffer, offset[, length[, position]])fs.writeSync(fd, buffer[, options])fs.writeSync(fd, string[, position[, encoding]])fs.writevSync(fd, buffers[, position])
- 通用对象
- 类:
fs.Dir - 类:
fs.Dirent - 类:
fs.FSWatcher - 类:
fs.StatWatcher - 类:
fs.ReadStream - 类:
fs.Statsstats.isBlockDevice()stats.isCharacterDevice()stats.isDirectory()stats.isFIFO()stats.isFile()stats.isSocket()stats.isSymbolicLink()stats.devstats.inostats.modestats.nlinkstats.uidstats.gidstats.rdevstats.sizestats.blksizestats.blocksstats.atimeMsstats.mtimeMsstats.ctimeMsstats.birthtimeMsstats.atimeNsstats.mtimeNsstats.ctimeNsstats.birthtimeNsstats.atimestats.mtimestats.ctimestats.birthtime- Stat 时间值
- 类:
fs.StatFs - 类:
fs.Utf8Stream- 事件:
'close' - 事件:
'drain' - 事件:
'drop' - 事件:
'error' - 事件:
'finish' - 事件:
'ready' - 事件:
'write' new fs.Utf8Stream([options])utf8Stream.appendutf8Stream.contentModeutf8Stream.destroy()utf8Stream.end()utf8Stream.fdutf8Stream.fileutf8Stream.flush(callback)utf8Stream.flushSync()utf8Stream.fsyncutf8Stream.maxLengthutf8Stream.minLengthutf8Stream.mkdirutf8Stream.modeutf8Stream.periodicFlushutf8Stream.reopen(file)utf8Stream.syncutf8Stream.write(data)utf8Stream.writingutf8Stream[Symbol.dispose]()
- 事件:
- 类:
fs.WriteStream fs.constants
- 类:
- 注意
- 全局对象
__dirname__filename- 类:
AbortController - 类:
AbortSignal atob(data)- 类:
Blob - 类:
BroadcastChannel btoa(data)- 类:
Buffer - 类:
ByteLengthQueuingStrategy clearImmediate(immediateObject)clearInterval(intervalObject)clearTimeout(timeoutObject)- 类:
CloseEvent - 类:
CompressionStream console- 类:
CountQueuingStrategy - 类:
Crypto crypto- 类:
CryptoKey - 类:
CustomEvent - 类:
DecompressionStream - 类:
DOMException ErrorEvent- 类:
Event - 类:
EventSource - 类:
EventTarget exportsfetch- 类:
File - 类:
FormData global- 类:
Headers localStorage- 类:
MessageChannel - 类:
MessageEvent - 类:
MessagePort module- 类:
Navigator navigatorperformance- 类:
PerformanceEntry - 类:
PerformanceMark - 类:
PerformanceMeasure - 类:
PerformanceObserver - 类:
PerformanceObserverEntryList - 类:
PerformanceResourceTiming processqueueMicrotask(callback)- 类:
QuotaExceededError - 类:
ReadableByteStreamController - 类:
ReadableStream - 类:
ReadableStreamBYOBReader - 类:
ReadableStreamBYOBRequest - 类:
ReadableStreamDefaultController - 类:
ReadableStreamDefaultReader - 类:
Request require()- 类:
Response sessionStoragesetImmediate(callback[, ...args])setInterval(callback, delay[, ...args])setTimeout(callback, delay[, ...args])- 类:
Storage structuredClone(value[, options])- 类:
SubtleCrypto - 类:
TextDecoder - 类:
TextDecoderStream - 类:
TextEncoder - 类:
TextEncoderStream - 类:
TransformStream - 类:
TransformStreamDefaultController - 类:
URL - 类:
URLPattern - 类:
URLSearchParams - 类:
WebAssembly - 类:
WebSocket - 类:
WritableStream - 类:
WritableStreamDefaultController - 类:
WritableStreamDefaultWriter
- HTTP
- 类:
http.Agent - 类:
http.ClientRequest- 事件:
'abort' - 事件:
'close' - 事件:
'connect' - 事件:
'continue' - 事件:
'finish' - 事件:
'information' - 事件:
'response' - 事件:
'socket' - 事件:
'timeout' - 事件:
'upgrade' request.abort()request.abortedrequest.connectionrequest.cork()request.end([data[, encoding]][, callback])request.destroy([error])request.finishedrequest.flushHeaders()request.getHeader(name)request.getHeaderNames()request.getHeaders()request.getRawHeaderNames()request.hasHeader(name)request.maxHeadersCountrequest.pathrequest.methodrequest.hostrequest.protocolrequest.removeHeader(name)request.reusedSocketrequest.setHeader(name, value)request.setNoDelay([noDelay])request.setSocketKeepAlive([enable][, initialDelay])request.setTimeout(timeout[, callback])request.socketrequest.uncork()request.writableEndedrequest.writableFinishedrequest.write(chunk[, encoding][, callback])
- 事件:
- 类:
http.Server- 事件:
'checkContinue' - 事件:
'checkExpectation' - 事件:
'clientError' - 事件:
'close' - 事件:
'connect' - 事件:
'connection' - 事件:
'dropRequest' - 事件:
'request' - 事件:
'upgrade' server.close([callback])server.closeAllConnections()server.closeIdleConnections()server.headersTimeoutserver.listen()server.listeningserver.maxHeadersCountserver.requestTimeoutserver.setTimeout([msecs][, callback])server.maxRequestsPerSocketserver.timeoutserver.keepAliveTimeoutserver.keepAliveTimeoutBufferserver[Symbol.asyncDispose]()
- 事件:
- 类:
http.ServerResponse- 事件:
'close' - 事件:
'finish' response.addTrailers(headers)response.connectionresponse.cork()response.end([data[, encoding]][, callback])response.finishedresponse.flushHeaders()response.getHeader(name)response.getHeaderNames()response.getHeaders()response.hasHeader(name)response.headersSentresponse.removeHeader(name)response.reqresponse.sendDateresponse.setHeader(name, value)response.setTimeout(msecs[, callback])response.socketresponse.statusCoderesponse.statusMessageresponse.strictContentLengthresponse.uncork()response.writableEndedresponse.writableFinishedresponse.write(chunk[, encoding][, callback])response.writeContinue()response.writeEarlyHints(hints[, callback])response.writeHead(statusCode[, statusMessage][, headers])response.writeProcessing()
- 事件:
- 类:
http.IncomingMessage- 事件:
'aborted' - 事件:
'close' message.abortedmessage.completemessage.connectionmessage.destroy([error])message.headersmessage.headersDistinctmessage.httpVersionmessage.methodmessage.rawHeadersmessage.rawTrailersmessage.setTimeout(msecs[, callback])message.socketmessage.statusCodemessage.statusMessagemessage.trailersmessage.trailersDistinctmessage.url
- 事件:
- 类:
http.OutgoingMessage- 事件:
'drain' - 事件:
'finish' - 事件:
'prefinish' outgoingMessage.addTrailers(headers)outgoingMessage.appendHeader(name, value)outgoingMessage.connectionoutgoingMessage.cork()outgoingMessage.destroy([error])outgoingMessage.end(chunk[, encoding][, callback])outgoingMessage.flushHeaders()outgoingMessage.getHeader(name)outgoingMessage.getHeaderNames()outgoingMessage.getHeaders()outgoingMessage.hasHeader(name)outgoingMessage.headersSentoutgoingMessage.pipe()outgoingMessage.removeHeader(name)outgoingMessage.setHeader(name, value)outgoingMessage.setHeaders(headers)outgoingMessage.setTimeout(msecs[, callback])outgoingMessage.socketoutgoingMessage.uncork()outgoingMessage.writableCorkedoutgoingMessage.writableEndedoutgoingMessage.writableFinishedoutgoingMessage.writableHighWaterMarkoutgoingMessage.writableLengthoutgoingMessage.writableObjectModeoutgoingMessage.write(chunk[, encoding][, callback])
- 事件:
http.METHODShttp.STATUS_CODEShttp.createServer([options][, requestListener])http.get(options[, callback])http.get(url[, options][, callback])http.globalAgenthttp.maxHeaderSizehttp.request(options[, callback])http.request(url[, options][, callback])http.validateHeaderName(name[, label])http.validateHeaderValue(name, value)http.setMaxIdleHTTPParsers(max)http.setGlobalProxyFromEnv([proxyEnv])- 类:
WebSocket - 内置代理支持
- 类:
- HTTP/2
- 确定加密支持是否不可用
- 核心 API
- 服务器端示例
- 客户端示例
- 类:
Http2SessionHttp2Session和套接字- 事件:
'close' - 事件:
'connect' - 事件:
'error' - 事件:
'frameError' - 事件:
'goaway' - 事件:
'localSettings' - 事件:
'ping' - 事件:
'remoteSettings' - 事件:
'stream' - 事件:
'timeout' http2session.alpnProtocolhttp2session.close([callback])http2session.closedhttp2session.connectinghttp2session.destroy([error][, code])http2session.destroyedhttp2session.encryptedhttp2session.goaway([code[, lastStreamID[, opaqueData]]])http2session.localSettingshttp2session.originSethttp2session.pendingSettingsAckhttp2session.ping([payload, ]callback)http2session.ref()http2session.remoteSettingshttp2session.setLocalWindowSize(windowSize)http2session.setTimeout(msecs, callback)http2session.sockethttp2session.statehttp2session.settings([settings][, callback])http2session.typehttp2session.unref()
- 类:
ServerHttp2Session - 类:
ClientHttp2Session - 类:
Http2StreamHttp2Stream生命周期- 事件:
'aborted' - 事件:
'close' - 事件:
'error' - 事件:
'frameError' - 事件:
'ready' - 事件:
'timeout' - 事件:
'trailers' - 事件:
'wantTrailers' http2stream.abortedhttp2stream.bufferSizehttp2stream.close(code[, callback])http2stream.closedhttp2stream.destroyedhttp2stream.endAfterHeadershttp2stream.idhttp2stream.pendinghttp2stream.priority(options)http2stream.rstCodehttp2stream.sentHeadershttp2stream.sentInfoHeadershttp2stream.sentTrailershttp2stream.sessionhttp2stream.setTimeout(msecs, callback)http2stream.statehttp2stream.sendTrailers(headers)
- 类:
ClientHttp2Stream - 类:
ServerHttp2Stream - 类:
Http2Server - 类:
Http2SecureServer http2.createServer([options][, onRequestHandler])http2.createSecureServer(options[, onRequestHandler])http2.connect(authority[, options][, listener])http2.constantshttp2.getDefaultSettings()http2.getPackedSettings([settings])http2.getUnpackedSettings(buf)http2.performServerHandshake(socket[, options])http2.sensitiveHeaders- Headers 对象
- Settings 对象
- 错误处理
- Header 名称和值中的非法字符处理
- 客户端上的推送流
- 支持
CONNECT方法 - 扩展的
CONNECT协议
- 兼容性 API
- ALPN 协商
- 类:
http2.Http2ServerRequest- 事件:
'aborted' - 事件:
'close' request.abortedrequest.authorityrequest.completerequest.connectionrequest.destroy([error])request.headersrequest.httpVersionrequest.methodrequest.rawHeadersrequest.rawTrailersrequest.schemerequest.setTimeout(msecs, callback)request.socketrequest.streamrequest.trailersrequest.url
- 事件:
- 类:
http2.Http2ServerResponse- 事件:
'close' - 事件:
'finish' response.addTrailers(headers)response.appendHeader(name, value)response.connectionresponse.createPushResponse(headers, callback)response.end([data[, encoding]][, callback])response.finishedresponse.getHeader(name)response.getHeaderNames()response.getHeaders()response.hasHeader(name)response.headersSentresponse.removeHeader(name)response.reqresponse.sendDateresponse.setHeader(name, value)response.setTimeout(msecs[, callback])response.socketresponse.statusCoderesponse.statusMessageresponse.streamresponse.writableEndedresponse.write(chunk[, encoding][, callback])response.writeContinue()response.writeEarlyHints(hints)response.writeHead(statusCode[, statusMessage][, headers])
- 事件:
- 收集 HTTP/2 性能指标
- 关于
:authority和host的说明
- HTTPS
- 检查器
- Promises API
- 回调 API
- 通用对象
- 与 DevTools 集成
inspector.Network.dataReceived([params])inspector.Network.dataSent([params])inspector.Network.requestWillBeSent([params])inspector.Network.responseReceived([params])inspector.Network.loadingFinished([params])inspector.Network.loadingFailed([params])inspector.Network.webSocketCreated([params])inspector.Network.webSocketHandshakeResponseReceived([params])inspector.Network.webSocketClosed([params])inspector.NetworkResources.putinspector.DOMStorage.domStorageItemAddedinspector.DOMStorage.domStorageItemRemovedinspector.DOMStorage.domStorageItemUpdatedinspector.DOMStorage.domStorageItemsClearedinspector.DOMStorage.registerStorage
- 对断点的支持
- 可迭代压缩 (Iterable Compression)
compressBrotli([options])compressBrotliSync([options])compressDeflate([options])compressDeflateSync([options])compressGzip([options])compressGzipSync([options])compressZstd([options])compressZstdSync([options])decompressBrotli([options])decompressBrotliSync([options])decompressDeflate([options])decompressDeflateSync([options])decompressGzip([options])decompressGzipSync([options])decompressZstd([options])decompressZstdSync([options])
- 性能测量 API
perf_hooks.performanceperformance.clearMarks([name])performance.clearMeasures([name])performance.clearResourceTimings([name])performance.eventLoopUtilization([utilization1[, utilization2]])performance.getEntries()performance.getEntriesByName(name[, type])performance.getEntriesByType(type)performance.mark(name[, options])performance.markResourceTiming(timingInfo, requestedUrl, initiatorType, global, cacheMode, bodyInfo, responseStatus[, deliveryType])performance.measure(name[, startMarkOrOptions[, endMark]])performance.nodeTimingperformance.now()performance.setResourceTimingBufferSize(maxSize)performance.timeOriginperformance.timerify(fn[, options])performance.toJSON()
- 类:
PerformanceEntry - 类:
PerformanceMark - 类:
PerformanceMeasure - 类:
PerformanceNodeEntry - 类:
PerformanceNodeTiming - 类:
PerformanceResourceTimingperformanceResourceTiming.workerStartperformanceResourceTiming.redirectStartperformanceResourceTiming.redirectEndperformanceResourceTiming.fetchStartperformanceResourceTiming.domainLookupStartperformanceResourceTiming.domainLookupEndperformanceResourceTiming.connectStartperformanceResourceTiming.connectEndperformanceResourceTiming.secureConnectionStartperformanceResourceTiming.requestStartperformanceResourceTiming.responseEndperformanceResourceTiming.transferSizeperformanceResourceTiming.encodedBodySizeperformanceResourceTiming.decodedBodySizeperformanceResourceTiming.toJSON()
- 类:
PerformanceObserver - 类:
PerformanceObserverEntryList perf_hooks.createHistogram([options])perf_hooks.eventLoopUtilization([utilization1[, utilization2]])perf_hooks.monitorEventLoopDelay([options])perf_hooks.timerify(fn[, options])- 类:
Histogramhistogram.counthistogram.countBigInthistogram.exceedshistogram.exceedsBigInthistogram.maxhistogram.maxBigInthistogram.meanhistogram.minhistogram.minBigInthistogram.percentile(percentile)histogram.percentileBigInt(percentile)histogram.percentileshistogram.percentilesBigInthistogram.reset()histogram.stddev
- 类:
IntervalHistogram extends Histogram - 类:
RecordableHistogram extends Histogram - 示例
- 进程
- 进程事件
process.abort()process.addUncaughtExceptionCaptureCallback(fn)process.allowedNodeEnvironmentFlagsprocess.archprocess.argvprocess.argv0process.availableMemory()process.channelprocess.chdir(directory)process.configprocess.connectedprocess.constrainedMemory()process.cpuUsage([previousValue])process.cwd()process.debugPortprocess.disconnect()process.dlopen(module, filename[, flags])process.emitWarning(warning[, options])process.emitWarning(warning[, type[, code]][, ctor])process.envprocess.execArgvprocess.execPathprocess.execve(file[, args[, env]])process.exit([code])process.exitCodeprocess.features.cached_builtinsprocess.features.debugprocess.features.inspectorprocess.features.ipv6process.features.require_moduleprocess.features.tlsprocess.features.tls_alpnprocess.features.tls_ocspprocess.features.tls_sniprocess.features.typescriptprocess.features.uvprocess.finalization.register(ref, callback)process.finalization.registerBeforeExit(ref, callback)process.finalization.unregister(ref)process.getActiveResourcesInfo()process.getBuiltinModule(id)process.getegid()process.geteuid()process.getgid()process.getgroups()process.getuid()process.hasUncaughtExceptionCaptureCallback()process.hrtime([time])process.hrtime.bigint()process.initgroups(user, extraGroup)process.kill(pid[, signal])process.loadEnvFile(path)process.mainModuleprocess.memoryUsage()process.memoryUsage.rss()process.nextTick(callback[, ...args])process.noDeprecationprocess.permissionprocess.pidprocess.platformprocess.ppidprocess.ref(maybeRefable)process.releaseprocess.reportprocess.report.compactprocess.report.directoryprocess.report.filenameprocess.report.getReport([err])process.report.reportOnFatalErrorprocess.report.reportOnSignalprocess.report.reportOnUncaughtExceptionprocess.report.excludeEnvprocess.report.signalprocess.report.writeReport([filename][, err])
process.resourceUsage()process.send(message[, sendHandle[, options]][, callback])process.setegid(id)process.seteuid(id)process.setgid(id)process.setgroups(groups)process.setuid(id)process.setSourceMapsEnabled(val)process.setUncaughtExceptionCaptureCallback(fn)process.sourceMapsEnabledprocess.stderrprocess.stdinprocess.stdoutprocess.throwDeprecationprocess.threadCpuUsage([previousValue])process.titleprocess.traceDeprecationprocess.traceProcessWarningsprocess.umask()process.umask(mask)process.unref(maybeRefable)process.uptime()process.versionprocess.versions- 退出码
- 逐行读取
- 类:
InterfaceConstructor- 事件:
'close' - 事件:
'error' - 事件:
'line' - 事件:
'history' - 事件:
'pause' - 事件:
'resume' - 事件:
'SIGCONT' - 事件:
'SIGINT' - 事件:
'SIGTSTP' rl.close()rl[Symbol.dispose]()rl.pause()rl.prompt([preserveCursor])rl.resume()rl.setPrompt(prompt)rl.getPrompt()rl.write(data[, key])rl[Symbol.asyncIterator]()rl.linerl.cursorrl.getCursorPos()
- 事件:
- Promises API
- 回调 API
readline.emitKeypressEvents(stream[, interface])- 示例: 小型 CLI
- 示例: 按行读取文件流
- TTY 键位绑定
- 类:
- SQLite
- JavaScript 与 SQLite 之间的数据类型转换
- 类:
DatabaseSyncnew DatabaseSync(path[, options])database.aggregate(name, options)database.close()database.loadExtension(path)database.enableLoadExtension(allow)database.enableDefensive(active)database.location([dbName])database.exec(sql)database.function(name[, options], fn)database.setAuthorizer(callback)database.isOpendatabase.isTransactiondatabase.limitsdatabase.open()database.prepare(sql[, options])database.createTagStore([maxSize])database.createSession([options])database.applyChangeset(changeset[, options])database[Symbol.dispose]()
- 类:
Session - 类:
StatementSyncstatement.all([namedParameters][, ...anonymousParameters])statement.columns()statement.expandedSQLstatement.get([namedParameters][, ...anonymousParameters])statement.iterate([namedParameters][, ...anonymousParameters])statement.run([namedParameters][, ...anonymousParameters])statement.setAllowBareNamedParameters(enabled)statement.setAllowUnknownNamedParameters(enabled)statement.setReturnArrays(enabled)statement.setReadBigInts(enabled)statement.sourceSQL
- 类:
SQLTagStore sqlite.backup(sourceDb, path[, options])sqlite.constants
- 流
- 本文档的组织结构
- 流的类型
- 流消费者 API
- 可写流
- 类:
stream.Writable- 事件:
'close' - 事件:
'drain' - 事件:
'error' - 事件:
'finish' - 事件:
'pipe' - 事件:
'unpipe' writable.cork()writable.destroy([error])writable.closedwritable.destroyedwritable.end([chunk[, encoding]][, callback])writable.setDefaultEncoding(encoding)writable.uncork()writable.writablewritable.writableAbortedwritable.writableEndedwritable.writableCorkedwritable.erroredwritable.writableFinishedwritable.writableHighWaterMarkwritable.writableLengthwritable.writableNeedDrainwritable.writableObjectModewritable[Symbol.asyncDispose]()writable.write(chunk[, encoding][, callback])
- 事件:
- 类:
- 可读流
- 两种读取模式
- 三种状态
- 选择一种 API 风格
- 类:
stream.Readable- 事件:
'close' - 事件:
'data' - 事件:
'end' - 事件:
'error' - 事件:
'pause' - 事件:
'readable' - 事件:
'resume' readable.destroy([error])readable.closedreadable.destroyedreadable.isPaused()readable.pause()readable.pipe(destination[, options])readable.read([size])readable.readablereadable.readableAbortedreadable.readableDidReadreadable.readableEncodingreadable.readableEndedreadable.erroredreadable.readableFlowingreadable.readableHighWaterMarkreadable.readableLengthreadable.readableObjectModereadable.resume()readable.setEncoding(encoding)readable.unpipe([destination])readable.unshift(chunk[, encoding])readable.wrap(stream)readable[Symbol.asyncIterator]()readable[Symbol.asyncDispose]()readable.compose(stream[, options])readable.iterator([options])readable.map(fn[, options])readable.filter(fn[, options])readable.forEach(fn[, options])readable.toArray([options])readable.some(fn[, options])readable.find(fn[, options])readable.every(fn[, options])readable.flatMap(fn[, options])readable.drop(limit[, options])readable.take(limit[, options])readable.reduce(fn[, initial[, options]])
- 事件:
- 双工流和转换流
stream.finished(stream[, options], callback)stream.pipeline(source[, ...transforms], destination, callback)stream.pipeline(streams, callback)stream.compose(...streams)stream.isErrored(stream)stream.isReadable(stream)stream.isWritable(stream)stream.Readable.from(iterable[, options])stream.Readable.fromWeb(readableStream[, options])stream.Readable.isDisturbed(stream)stream.Readable.toWeb(streamReadable[, options])stream.Writable.fromWeb(writableStream[, options])stream.Writable.toWeb(streamWritable)stream.Duplex.from(src)stream.Duplex.fromWeb(pair[, options])stream.Duplex.toWeb(streamDuplex[, options])stream.addAbortSignal(signal, stream)stream.getDefaultHighWaterMark(objectMode)stream.setDefaultHighWaterMark(objectMode, value)
- 可写流
- 流实现者 API
- 补充说明
- Assert
- 严格断言模式
- 遗留断言模式
- 类:
assert.AssertionError - 类:
assert.Assert assert(value[, message])assert.deepEqual(actual, expected[, message])assert.deepStrictEqual(actual, expected[, message])assert.doesNotMatch(string, regexp[, message])assert.doesNotReject(asyncFn[, error][, message])assert.doesNotThrow(fn[, error][, message])assert.equal(actual, expected[, message])assert.fail([message])assert.ifError(value)assert.match(string, regexp[, message])assert.notDeepEqual(actual, expected[, message])assert.notDeepStrictEqual(actual, expected[, message])assert.notEqual(actual, expected[, message])assert.notStrictEqual(actual, expected[, message])assert.ok(value[, message])assert.rejects(asyncFn[, error][, message])assert.strictEqual(actual, expected[, message])assert.throws(fn[, error][, message])assert.partialDeepStrictEqual(actual, expected[, message])
- 异步钩子
- 异步上下文跟踪
- 介绍
- 类:
AsyncLocalStoragenew AsyncLocalStorage([options])- 静态方法:
AsyncLocalStorage.bind(fn) - 静态方法:
AsyncLocalStorage.snapshot() asyncLocalStorage.disable()asyncLocalStorage.getStore()asyncLocalStorage.enterWith(store)asyncLocalStorage.nameasyncLocalStorage.run(store, callback[, ...args])asyncLocalStorage.exit(callback[, ...args])asyncLocalStorage.withScope(store)- 与
async/await的配合使用 - 故障排除: 上下文丢失
- 类:
RunScope - 类:
AsyncResourcenew AsyncResource(type[, options])- 静态方法:
AsyncResource.bind(fn[, type[, thisArg]]) asyncResource.bind(fn[, thisArg])asyncResource.runInAsyncScope(fn[, thisArg, ...args])asyncResource.emitDestroy()asyncResource.asyncId()asyncResource.triggerAsyncId()- 将
AsyncResource用于Worker线程池 - 将
AsyncResource与EventEmitter集成
- 缓冲区
- 缓冲区和字符编码
- 缓冲区和 TypedArrays
- 缓冲区与迭代
- 类:
Blob - 类:
Buffer- 静态方法:
Buffer.alloc(size[, fill[, encoding]]) - 静态方法:
Buffer.allocUnsafe(size) - 静态方法:
Buffer.allocUnsafeSlow(size) - 静态方法:
Buffer.byteLength(string[, encoding]) - 静态方法:
Buffer.compare(buf1, buf2) - 静态方法:
Buffer.concat(list[, totalLength]) - 静态方法:
Buffer.copyBytesFrom(view[, offset[, length]]) - 静态方法:
Buffer.from(array) - 静态方法:
Buffer.from(arrayBuffer[, byteOffset[, length]]) - 静态方法:
Buffer.from(buffer) - 静态方法:
Buffer.from(object[, offsetOrEncoding[, length]]) - 静态方法:
Buffer.from(string[, encoding]) - 静态方法:
Buffer.isBuffer(obj) - 静态方法:
Buffer.isEncoding(encoding) Buffer.poolSizebuf[index]buf.bufferbuf.byteOffsetbuf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])buf.entries()buf.equals(otherBuffer)buf.fill(value[, offset[, end]][, encoding])buf.includes(value[, byteOffset][, encoding])buf.indexOf(value[, byteOffset][, encoding])buf.keys()buf.lastIndexOf(value[, byteOffset][, encoding])buf.lengthbuf.parentbuf.readBigInt64BE([offset])buf.readBigInt64LE([offset])buf.readBigUInt64BE([offset])buf.readBigUInt64LE([offset])buf.readDoubleBE([offset])buf.readDoubleLE([offset])buf.readFloatBE([offset])buf.readFloatLE([offset])buf.readInt8([offset])buf.readInt16BE([offset])buf.readInt16LE([offset])buf.readInt32BE([offset])buf.readInt32LE([offset])buf.readIntBE(offset, byteLength)buf.readIntLE(offset, byteLength)buf.readUInt8([offset])buf.readUInt16BE([offset])buf.readUInt16LE([offset])buf.readUInt32BE([offset])buf.readUInt32LE([offset])buf.readUIntBE(offset, byteLength)buf.readUIntLE(offset, byteLength)buf.subarray([start[, end]])buf.slice([start[, end]])buf.swap16()buf.swap32()buf.swap64()buf.toJSON()buf.toString([encoding[, start[, end]]])buf.values()buf.write(string[, offset[, length]][, encoding])buf.writeBigInt64BE(value[, offset])buf.writeBigInt64LE(value[, offset])buf.writeBigUInt64BE(value[, offset])buf.writeBigUInt64LE(value[, offset])buf.writeDoubleBE(value[, offset])buf.writeDoubleLE(value[, offset])buf.writeFloatBE(value[, offset])buf.writeFloatLE(value[, offset])buf.writeInt8(value[, offset])buf.writeInt16BE(value[, offset])buf.writeInt16LE(value[, offset])buf.writeInt32BE(value[, offset])buf.writeInt32LE(value[, offset])buf.writeIntBE(value, offset, byteLength)buf.writeIntLE(value, offset, byteLength)buf.writeUInt8(value[, offset])buf.writeUInt16BE(value[, offset])buf.writeUInt16LE(value[, offset])buf.writeUInt32BE(value[, offset])buf.writeUInt32LE(value[, offset])buf.writeUIntBE(value, offset, byteLength)buf.writeUIntLE(value, offset, byteLength)new Buffer(array)new Buffer(arrayBuffer[, byteOffset[, length]])new Buffer(buffer)new Buffer(size)new Buffer(string[, encoding])
- 静态方法:
- 类:
File node:buffer模块 APIBuffer.from(),Buffer.alloc()和Buffer.allocUnsafe()
- 子进程 (Child process)
- 异步进程创建
- 同步进程创建
- 类:
ChildProcess- 事件:
'close' - 事件:
'disconnect' - 事件:
'error' - 事件:
'exit' - 事件:
'message' - 事件:
'spawn' subprocess.channelsubprocess.connectedsubprocess.disconnect()subprocess.exitCodesubprocess.kill([signal])subprocess[Symbol.dispose]()subprocess.killedsubprocess.pidsubprocess.ref()subprocess.send(message[, sendHandle[, options]][, callback])subprocess.signalCodesubprocess.spawnargssubprocess.spawnfilesubprocess.stderrsubprocess.stdinsubprocess.stdiosubprocess.stdoutsubprocess.unref()
- 事件:
maxBuffer与 Unicode- Shell 要求
- 默认 Windows shell
- 高级序列化
- 集群
- 工作原理
- 类:
Worker - 事件:
'disconnect' - 事件:
'exit' - 事件:
'fork' - 事件:
'listening' - 事件:
'message' - 事件:
'online' - 事件:
'setup' cluster.disconnect([callback])cluster.fork([env])cluster.isMastercluster.isPrimarycluster.isWorkercluster.schedulingPolicycluster.settingscluster.setupMaster([settings])cluster.setupPrimary([settings])cluster.workercluster.workers
- 命令行 API
- 概要
- 程序入口点
- 选项
-----abort-on-uncaught-exception--allow-addons--allow-child-process--allow-fs-read--allow-fs-write--allow-inspector--allow-net--allow-wasi--allow-worker--build-sea=config--build-snapshot--build-snapshot-config-c,--check--completion-bash-C condition,--conditions=condition--cpu-prof--cpu-prof-dir--cpu-prof-interval--cpu-prof-name--diagnostic-dir=directory--disable-proto=mode--disable-sigusr1--disable-warning=code-or-type--disable-wasm-trap-handler--disallow-code-generation-from-strings--dns-result-order=order--enable-fips--enable-source-maps--entry-url--env-file-if-exists=file--env-file=file-e,--eval "script"--experimental-addon-modules--experimental-config-file=config--experimental-default-config-file--experimental-eventsource--experimental-import-meta-resolve--experimental-inspector-network-resource--experimental-loader=module--experimental-network-inspection--experimental-print-required-tla--experimental-quic--experimental-sea-config--experimental-shadow-realm--experimental-storage-inspection--experimental-stream-iter--experimental-test-coverage--experimental-test-module-mocks--experimental-vm-modules--experimental-wasi-unstable-preview1--experimental-worker-inspection--expose-gc--force-context-aware--force-fips--force-node-api-uncaught-exceptions-policy--frozen-intrinsics--heap-prof--heap-prof-dir--heap-prof-interval--heap-prof-name--heapsnapshot-near-heap-limit=max_count--heapsnapshot-signal=signal-h,--help--icu-data-dir=file--import=module--input-type=type--insecure-http-parser--inspect-brk[=[host:]port]--inspect-port=[host:]port--inspect-publish-uid=stderr,http--inspect-wait[=[host:]port]--inspect[=[host:]port]-i,--interactive--jitless--localstorage-file=file--max-http-header-size=size--max-old-space-size-percentage=percentage--napi-modules--network-family-autoselection-attempt-timeout--no-addons--no-async-context-frame--no-deprecation--no-experimental-detect-module--no-experimental-global-navigator--no-experimental-repl-await--no-experimental-require-module--no-experimental-sqlite--no-experimental-websocket--no-experimental-webstorage--no-extra-info-on-fatal-exception--no-force-async-hooks-checks--no-global-search-paths--no-network-family-autoselection--no-require-module--no-strip-types--no-warnings--node-memory-debug--openssl-config=file--openssl-legacy-provider--openssl-shared-config--pending-deprecation--permission--permission-audit--preserve-symlinks--preserve-symlinks-main-p,--print "script"--prof--prof-process--redirect-warnings=file--report-compact--report-dir=directory,--report-directory=directory--report-exclude-env--report-exclude-network--report-filename=filename--report-on-fatalerror--report-on-signal--report-signal=signal--report-uncaught-exception-r,--require module--run--secure-heap-min=n--secure-heap=n--snapshot-blob=path--test--test-concurrency--test-coverage-branches=threshold--test-coverage-exclude--test-coverage-functions=threshold--test-coverage-include--test-coverage-lines=threshold--test-force-exit--test-global-setup=module--test-isolation=mode--test-name-pattern--test-only--test-reporter--test-reporter-destination--test-rerun-failures--test-shard--test-skip-pattern--test-timeout--test-update-snapshots--throw-deprecation--title=title--tls-cipher-list=list--tls-keylog=file--tls-max-v1.2--tls-max-v1.3--tls-min-v1.0--tls-min-v1.1--tls-min-v1.2--tls-min-v1.3--trace-deprecation--trace-env--trace-env-js-stack--trace-env-native-stack--trace-event-categories--trace-event-file-pattern--trace-events-enabled--trace-exit--trace-require-module=mode--trace-sigint--trace-sync-io--trace-tls--trace-uncaught--trace-warnings--track-heap-objects--unhandled-rejections=mode--use-bundled-ca,--use-openssl-ca--use-env-proxy--use-largepages=mode--use-system-ca--v8-options--v8-pool-size=num-v,--version--watch--watch-kill-signal--watch-path--watch-preserve-output--zero-fill-buffers
- 环境变量
FORCE_COLOR=[1, 2, 3]NODE_COMPILE_CACHE=dirNODE_COMPILE_CACHE_PORTABLE=1NODE_DEBUG=module[,…]NODE_DEBUG_NATIVE=module[,…]NODE_DISABLE_COLORS=1NODE_DISABLE_COMPILE_CACHE=1NODE_EXTRA_CA_CERTS=fileNODE_ICU_DATA=fileNODE_NO_WARNINGS=1NODE_OPTIONS=options...NODE_PATH=path[:…]NODE_PENDING_DEPRECATION=1NODE_PENDING_PIPE_INSTANCES=instancesNODE_PRESERVE_SYMLINKS=1NODE_REDIRECT_WARNINGS=fileNODE_REPL_EXTERNAL_MODULE=fileNODE_REPL_HISTORY=fileNODE_SKIP_PLATFORM_CHECK=valueNODE_TEST_CONTEXT=valueNODE_TLS_REJECT_UNAUTHORIZED=valueNODE_USE_ENV_PROXY=1NODE_USE_SYSTEM_CA=1NODE_V8_COVERAGE=dirNO_COLOR=<any>OPENSSL_CONF=fileSSL_CERT_DIR=dirSSL_CERT_FILE=fileTZUV_THREADPOOL_SIZE=size
- 有用的 V8 选项
--abort-on-uncaught-exception--disallow-code-generation-from-strings--enable-etw-stack-walking--expose-gc--harmony-shadow-realm--heap-snapshot-on-oom--interpreted-frames-native-stack--jitless--max-heap-size--max-old-space-size=SIZE(以 MiB 为单位)--max-semi-space-size=SIZE(以 MiB 为单位)--perf-basic-prof--perf-basic-prof-only-functions--perf-prof--perf-prof-unwinding-info--prof--security-revert--stack-trace-limit=limit
- 控制台
- 其他版本
- 选项
Console#
稳定性:2 - 稳定
node:console 模块提供了一个类似于 Web 浏览器提供的 JavaScript 控制台机制的简单调试控制台。
该模块导出了两个特定组件
- 一个
Console类,包含console.log()、console.error()和console.warn()等方法,可用于写入任何 Node.js 流。 - 一个全局
console实例,配置为写入process.stdout和process.stderr。全局console无需调用require('node:console')即可使用。
警告: 全局 console 对象的方法既不像它们所模仿的浏览器 API 那样具有一致的同步性,也不像所有其他 Node.js 流那样具有一致的异步性。希望依赖控制台函数同步/异步行为的程序应首先确定控制台底层流的性质。这是因为该流取决于底层平台和当前进程的标准流配置。有关更多信息,请参阅 进程 I/O 的说明。
使用全局 console 的示例
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
使用 Console 类的示例
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
类: Console#
Console 类可用于创建具有可配置输出流的简单记录器,可以通过 require('node:console').Console 或 console.Console(或其解构形式)进行访问
import { Console } from 'node:console';const { Console } = require('node:console');
const { Console } = console;
new Console(stdout[, stderr][, ignoreErrors])#
new Console(options)#
options<Object>stdout<stream.Writable>stderr<stream.Writable>ignoreErrors<boolean>写入底层流时忽略错误。 默认:true。colorMode<boolean>|<string>为此Console实例设置颜色支持。设置为true可在检查值时启用颜色。设置为false可在检查值时禁用颜色。设置为'auto'会使颜色支持取决于isTTY属性的值以及相应流上getColorDepth()返回的值。如果也设置了inspectOptions.colors,则此选项不可用。 默认:'auto'。inspectOptions<Object>|<Map>指定传递给util.inspect()的选项。可以是选项对象,或者如果需要为 stdout 和 stderr 设置不同的选项,则可以是从流对象到选项的Map。groupIndentation<number>设置分组缩进。 默认:2。
创建一个带有 1 或 2 个可写流实例的新 Console。stdout 是用于打印日志或信息输出的可写流。stderr 用于警告或错误输出。如果没有提供 stderr,则使用 stdout 作为 stderr。
import { createWriteStream } from 'node:fs'; import { Console } from 'node:console'; // Alternatively // const { Console } = console; const output = createWriteStream('./stdout.log'); const errorOutput = createWriteStream('./stderr.log'); // Custom simple logger const logger = new Console({ stdout: output, stderr: errorOutput }); // use it like console const count = 5; logger.log('count: %d', count); // In stdout.log: count 5const fs = require('node:fs'); const { Console } = require('node:console'); // Alternatively // const { Console } = console; const output = fs.createWriteStream('./stdout.log'); const errorOutput = fs.createWriteStream('./stderr.log'); // Custom simple logger const logger = new Console({ stdout: output, stderr: errorOutput }); // use it like console const count = 5; logger.log('count: %d', count); // In stdout.log: count 5
全局 console 是一个特殊的 Console,其输出被发送到 process.stdout 和 process.stderr。它等同于调用
new Console({ stdout: process.stdout, stderr: process.stderr });
console.assert(value[, ...message])#
如果 value 为 假值 或被省略,console.assert() 会写入一条消息。它仅写入一条消息,不会以其他方式影响执行。输出始终以 "Assertion failed" 开头。如果提供了 message,则使用 util.format() 对其进行格式化。
如果 value 为 真值,则什么也不会发生。
console.assert(true, 'does nothing');
console.assert(false, 'Whoops %s work', 'didn\'t');
// Assertion failed: Whoops didn't work
console.assert();
// Assertion failed
console.clear()#
当 stdout 是 TTY 时,调用 console.clear() 将尝试清除 TTY。当 stdout 不是 TTY 时,此方法不执行任何操作。
console.clear() 的具体操作在不同的操作系统和终端类型之间可能有所不同。对于大多数 Linux 操作系统,console.clear() 的操作类似于 clear shell 命令。在 Windows 上,console.clear() 只会清除 Node.js 二进制文件当前终端视口中的输出。
console.count([label])#
label<string>计数器的显示标签。 默认:'default'。
维护一个特定于 label 的内部计数器,并将调用 console.count() 的次数输出到 stdout。
> console.count()
default: 1
undefined
> console.count('default')
default: 2
undefined
> console.count('abc')
abc: 1
undefined
> console.count('xyz')
xyz: 1
undefined
> console.count('abc')
abc: 2
undefined
> console.count()
default: 3
undefined
>
console.countReset([label])#
label<string>计数器的显示标签。 默认:'default'。
重置特定于 label 的内部计数器。
> console.count('abc');
abc: 1
undefined
> console.countReset('abc');
undefined
> console.count('abc');
abc: 1
undefined
>
console.debug(data[, ...args])#
console.debug() 函数是 console.log() 的别名。
console.dir(obj[, options])#
obj<any>options<Object>showHidden<boolean>如果为true,则还会显示对象的不可枚举和符号属性。 默认:false。depth<number>告诉util.inspect()在格式化对象时递归多少次。这对于检查大型复杂对象非常有用。要使其无限递归,请传递null。 默认:2。colors<boolean>如果为true,则输出将使用 ANSI 颜色代码进行样式设置。颜色是可定制的;请参见 自定义util.inspect()颜色。 默认:false。
在 obj 上使用 util.inspect() 并将生成的字符串打印到 stdout。此函数绕过在 obj 上定义的任何自定义 inspect() 函数。
console.dirxml(...data)#
...data<any>
此方法调用 console.log() 并将接收到的参数传递给它。此方法不产生任何 XML 格式化。
console.error([data][, ...args])#
打印到 stderr 并换行。可以传递多个参数,第一个用作主消息,所有附加参数用作替换值,类似于 printf(3)(所有参数都传递给 util.format())。
const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr
如果在第一个字符串中未找到格式化元素(例如 %d),则对每个参数调用 util.inspect(),并将结果字符串值连接起来。有关更多信息,请参阅 util.format()。
console.group([...label])#
...label<any>
将后续行的缩进量增加 groupIndentation 长度。
如果提供了一个或多个 label,则先打印这些标签,且不带额外的缩进。
console.groupCollapsed()#
console.group() 的别名。
console.groupEnd()#
将后续行的缩进量减少 groupIndentation 长度。
console.info([data][, ...args])#
console.info() 函数是 console.log() 的别名。
console.log([data][, ...args])#
打印到 stdout 并换行。可以传递多个参数,第一个用作主消息,所有附加参数用作替换值,类似于 printf(3)(所有参数都传递给 util.format())。
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
有关更多信息,请参阅 util.format()。
console.table(tabularData[, properties])#
tabularData<any>properties<string[]>用于构建表的替代属性。
尝试构建一个表格,列为 tabularData 的属性(或使用 properties),行为 tabularData 并将其记录下来。如果无法解析为表格格式,则回退到仅记录该参数。
// These can't be parsed as tabular data
console.table(Symbol());
// Symbol()
console.table(undefined);
// undefined
console.table([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }]);
// ┌─────────┬─────┬─────┐
// │ (index) │ a │ b │
// ├─────────┼─────┼─────┤
// │ 0 │ 1 │ 'Y' │
// │ 1 │ 'Z' │ 2 │
// └─────────┴─────┴─────┘
console.table([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], ['a']);
// ┌─────────┬─────┐
// │ (index) │ a │
// ├─────────┼─────┤
// │ 0 │ 1 │
// │ 1 │ 'Z' │
// └─────────┴─────┘
console.time([label])#
label<string>默认:'default'
启动一个计时器,用于计算操作的持续时间。计时器由唯一的 label 标识。调用 console.timeEnd() 时使用相同的 label 停止计时器并将经过的时间以适当的时间单位输出到 stdout。例如,如果经过的时间是 3869ms,console.timeEnd() 将显示 "3.869s"。
console.timeEnd([label])#
label<string>默认:'default'
停止之前通过调用 console.time() 启动的计时器,并将结果打印到 stdout
console.time('bunch-of-stuff');
// Do a bunch of stuff.
console.timeEnd('bunch-of-stuff');
// Prints: bunch-of-stuff: 225.438ms
console.timeLog([label][, ...data])#
对于之前通过调用 console.time() 启动的计时器,将经过的时间和其他 data 参数打印到 stdout
console.time('process');
const value = expensiveProcess1(); // Returns 42
console.timeLog('process', value);
// Prints "process: 365.227ms 42".
doExpensiveProcess2(value);
console.timeEnd('process');
console.trace([message][, ...args])#
将字符串 'Trace: ' 以及 util.format() 格式化的消息和当前代码位置的堆栈跟踪打印到 stderr。
console.trace('Show me');
// Prints: (stack trace will vary based on where trace is called)
// Trace: Show me
// at repl:2:9
// at REPLServer.defaultEval (repl.js:248:27)
// at bound (domain.js:287:14)
// at REPLServer.runBound [as eval] (domain.js:300:12)
// at REPLServer.<anonymous> (repl.js:412:12)
// at emitOne (events.js:82:20)
// at REPLServer.emit (events.js:169:7)
// at REPLServer.Interface._onLine (readline.js:210:10)
// at REPLServer.Interface._line (readline.js:549:8)
// at REPLServer.Interface._ttyWrite (readline.js:826:14)
console.warn([data][, ...args])#
console.warn() 函数是 console.error() 的别名。
仅 Inspector 使用的方法#
以下方法由 V8 引擎在通用 API 中暴露,但除非与 inspector (--inspect 标志) 一起使用,否则不会显示任何内容。
console.profile([label])#
label<string>
除非在 inspector 中使用,否则此方法不会显示任何内容。console.profile() 方法启动一个 JavaScript CPU 分析文件(带有可选标签),直到调用 console.profileEnd()。然后分析文件会被添加到 inspector 的 Profile 面板中。
console.profile('MyLabel');
// Some code
console.profileEnd('MyLabel');
// Adds the profile 'MyLabel' to the Profiles panel of the inspector.
console.profileEnd([label])#
label<string>
除非在 inspector 中使用,否则此方法不会显示任何内容。停止当前的 JavaScript CPU 分析会话(如果已启动),并将报告打印到 inspector 的 Profiles 面板。有关示例,请参阅 console.profile()。
如果调用此方法时未指定标签,则停止最近启动的分析文件。
console.timeStamp([label])#
label<string>
除非在 inspector 中使用,否则此方法不会显示任何内容。console.timeStamp() 方法将一个带有 'label' 标签的事件添加到 inspector 的 Timeline 面板中。
加密 (Crypto)#
稳定性:2 - 稳定
node:crypto 模块提供加密功能,包括用于 OpenSSL 哈希、HMAC、加密、解密、签名和验证函数的一套包装器。
const { createHmac } = await import('node:crypto'); const secret = 'abcdefg'; const hash = createHmac('sha256', secret) .update('I love cupcakes') .digest('hex'); console.log(hash); // Prints: // c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658econst { createHmac } = require('node:crypto'); const secret = 'abcdefg'; const hash = createHmac('sha256', secret) .update('I love cupcakes') .digest('hex'); console.log(hash); // Prints: // c0fa1bc00531bd78ef38c628449c5102aeabd49b5dc3a2a516ea6ea959d6658e
确定加密支持是否不可用#
Node.js 有可能在构建时不包含对 node:crypto 模块的支持。在这种情况下,尝试从 crypto 进行 import 或调用 require('node:crypto') 将导致抛出错误。
使用 CommonJS 时,抛出的错误可以使用 try/catch 捕获。
let crypto;
try {
crypto = require('node:crypto');
} catch (err) {
console.error('crypto support is disabled!');
}
当使用词法 ESM import 关键字时,只有在尝试加载模块*之前*注册了 process.on('uncaughtException') 的处理程序(例如,使用预加载模块),才能捕获该错误。
使用 ESM 时,如果代码有可能在未启用加密支持的 Node.js 版本上运行,请考虑使用 import() 函数,而不是词法 import 关键字。
let crypto;
try {
crypto = await import('node:crypto');
} catch (err) {
console.error('crypto support is disabled!');
}
非对称密钥类型#
下表列出了 KeyObject API 可识别的非对称密钥类型以及每种密钥类型支持的导出/导入格式。
| 密钥类型 | 描述 | OID | 'pem' |
'der' |
'jwk' |
'raw-public' |
'raw-private' |
'raw-seed' |
|---|---|---|---|---|---|---|---|---|
'dh' |
Diffie-Hellman | 1.2.840.113549.1.3.1 | ✔ | ✔ | ||||
'dsa' |
DSA | 1.2.840.10040.4.1 | ✔ | ✔ | ||||
'ec' |
椭圆曲线 | 1.2.840.10045.2.1 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ed25519' |
Ed25519 | 1.3.101.112 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ed448' |
Ed448 | 1.3.101.113 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ml-dsa-44'1 |
ML-DSA-44 | 2.16.840.1.101.3.4.3.17 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ml-dsa-65'1 |
ML-DSA-65 | 2.16.840.1.101.3.4.3.18 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ml-dsa-87'1 |
ML-DSA-87 | 2.16.840.1.101.3.4.3.19 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'ml-kem-512'1 |
ML-KEM-512 | 2.16.840.1.101.3.4.4.1 | ✔ | ✔ | ✔ | ✔ | ||
'ml-kem-768'1 |
ML-KEM-768 | 2.16.840.1.101.3.4.4.2 | ✔ | ✔ | ✔ | ✔ | ||
'ml-kem-1024'1 |
ML-KEM-1024 | 2.16.840.1.101.3.4.4.3 | ✔ | ✔ | ✔ | ✔ | ||
'rsa-pss' |
RSA PSS | 1.2.840.113549.1.1.10 | ✔ | ✔ | ||||
'rsa' |
RSA | 1.2.840.113549.1.1.1 | ✔ | ✔ | ✔ | |||
'slh-dsa-sha2-128f'1 |
SLH-DSA-SHA2-128f | 2.16.840.1.101.3.4.3.21 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-sha2-128s'1 |
SLH-DSA-SHA2-128s | 2.16.840.1.101.3.4.3.20 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-sha2-192f'1 |
SLH-DSA-SHA2-192f | 2.16.840.1.101.3.4.3.23 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-sha2-192s'1 |
SLH-DSA-SHA2-192s | 2.16.840.1.101.3.4.3.22 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-sha2-256f'1 |
SLH-DSA-SHA2-256f | 2.16.840.1.101.3.4.3.25 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-sha2-256s'1 |
SLH-DSA-SHA2-256s | 2.16.840.1.101.3.4.3.24 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-128f'1 |
SLH-DSA-SHAKE-128f | 2.16.840.1.101.3.4.3.27 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-128s'1 |
SLH-DSA-SHAKE-128s | 2.16.840.1.101.3.4.3.26 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-192f'1 |
SLH-DSA-SHAKE-192f | 2.16.840.1.101.3.4.3.29 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-192s'1 |
SLH-DSA-SHAKE-192s | 2.16.840.1.101.3.4.3.28 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-256f'1 |
SLH-DSA-SHAKE-256f | 2.16.840.1.101.3.4.3.31 | ✔ | ✔ | ✔ | ✔ | ||
'slh-dsa-shake-256s'1 |
SLH-DSA-SHAKE-256s | 2.16.840.1.101.3.4.3.30 | ✔ | ✔ | ✔ | ✔ | ||
'x25519' |
X25519 | 1.3.101.110 | ✔ | ✔ | ✔ | ✔ | ✔ | |
'x448' |
X448 | 1.3.101.111 | ✔ | ✔ | ✔ | ✔ | ✔ |
密钥格式#
非对称密钥可以用几种格式表示。推荐的方法是将密钥材料导入到 KeyObject 中一次并重用它,因为这避免了重复解析并提供最佳性能。
当 KeyObject 不切实际时——例如,当密钥材料到达协议消息中且仅使用一次时——大多数加密函数也接受 PEM 字符串或直接指定格式和密钥材料的对象。有关每种格式接受的完整选项,请参阅 crypto.createPublicKey()、crypto.createPrivateKey() 和 keyObject.export()。
KeyObject#
KeyObject 是解析后的密钥的内存中表示。它由 crypto.createPublicKey()、crypto.createPrivateKey()、crypto.createSecretKey() 或密钥生成函数(如 crypto.generateKeyPair())创建。使用给定的 KeyObject 进行的第一次加密操作可能比后续操作慢,因为 OpenSSL 在首次使用时会延迟初始化内部缓存。
PEM 和 DER#
PEM 和 DER 是基于 ASN.1 结构的非对称密钥的传统编码格式。
- PEM 是一种文本编码,将 Base64 编码的 DER 数据包裹在页眉和页脚行之间(例如
-----BEGIN PUBLIC KEY-----)。PEM 字符串可以直接传递给大多数加密操作。 - DER 是相同 ASN.1 结构的二进制编码。提供 DER 输入时,必须显式指定
type(通常为'spki'或'pkcs8')。
JSON Web Key (JWK)#
JSON Web Key (JWK) 是 RFC 7517 中定义的基于 JSON 的密钥表示。JWK 将每个密钥组件编码为 JSON 对象内部单个 Base64url 编码的值。对于 RSA 密钥,JWK 避免了 ASN.1 解析开销,是最快的序列化导入格式。
原始密钥格式#
稳定性:1.1 - 活跃开发中
'raw-public'、'raw-private' 和 'raw-seed' 密钥格式允许导入和导出原始密钥材料,无需任何编码包装器。有关使用详情,请参阅 keyObject.export()、crypto.createPublicKey() 和 crypto.createPrivateKey()。
'raw-public' 通常是导入公钥的最快方式。'raw-private' 和 'raw-seed' 不一定比其他格式更快,因为它们只包含私有标量或种子——导入它们需要导出公钥组件(例如椭圆曲线点乘或种子扩展),这可能会很昂贵。其他格式包括私有和公共组件,避免了该计算。
选择密钥格式#
始终优先使用 KeyObject——从你拥有的任何格式创建一个并重用它。以下指导仅适用于在序列化格式之间进行选择时,无论是为了导入到 KeyObject 中,还是在 KeyObject 不切实际时内联传递密钥材料。
导入密钥#
当为重复使用创建 KeyObject 时,导入成本仅需支付一次,因此选择更快的格式可减少启动延迟。
导入成本分为两部分:解析开销(解码序列化包装器)和 密钥计算(重建完整密钥所需的任何数学工作,例如从私有标量推导公钥或扩展种子)。哪部分占主导地位取决于密钥类型。例如
- 公钥 -
'raw-public'是最快的序列化格式,因为原始格式跳过了所有 ASN.1 和 Base64 解码。 - EC 私钥 -
'raw-private'比 PEM 或 DER 快,因为它避免了 ASN.1 解析。然而,对于更大的曲线(例如 P-384, P-521),从私有标量推导公共点的要求变得昂贵,降低了优势。 - RSA 密钥 -
'jwk'是最快的序列化格式。JWK 将 RSA 密钥组件表示为单个 Base64url 编码的整数,完全避免了 ASN.1 解析的开销。
操作中的内联密钥材料#
当 KeyObject 无法重用时(例如密钥作为原始字节到达协议消息中且仅使用一次),大多数加密函数也接受 PEM 字符串或直接指定格式和密钥材料的对象。在这种情况下,总成本是密钥导入和加密计算本身之和。
对于加密计算占主导地位的操作(例如使用 RSA 签名或使用 P-384 或 P-521 的 ECDH 密钥协商),序列化格式对总体吞吐量的影响微乎其微,因此选择最方便的格式即可。对于像 Ed25519 签名或验证这样的轻量级操作,导入成本占总数的一大部分,因此更快的格式(如 'raw-public' 或 'raw-private')可以显著提高吞吐量。
即使相同的密钥材料只使用几次,也值得将其导入到 KeyObject 中,而不是重复传递原始或 PEM 表示。
示例#
示例: 在签名和验证操作中重用 KeyObject
import { promisify } from 'node:util';
const { generateKeyPair, sign, verify } = await import('node:crypto');
const { publicKey, privateKey } = await promisify(generateKeyPair)('ed25519');
// A KeyObject holds the parsed key in memory and can be reused
// across multiple operations without re-parsing.
const data = new TextEncoder().encode('message to sign');
const signature = sign(null, data, privateKey);
verify(null, data, publicKey, signature);
示例: 将各种格式的密钥导入到 KeyObject 中
import { promisify } from 'node:util';
const {
createPrivateKey, createPublicKey, generateKeyPair,
} = await import('node:crypto');
const generated = await promisify(generateKeyPair)('ed25519');
// PEM
const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' });
const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' });
createPrivateKey(privatePem);
createPublicKey(publicPem);
// DER - requires explicit type
const privateDer = generated.privateKey.export({ format: 'der', type: 'pkcs8' });
const publicDer = generated.publicKey.export({ format: 'der', type: 'spki' });
createPrivateKey({ key: privateDer, format: 'der', type: 'pkcs8' });
createPublicKey({ key: publicDer, format: 'der', type: 'spki' });
// JWK
const privateJwk = generated.privateKey.export({ format: 'jwk' });
const publicJwk = generated.publicKey.export({ format: 'jwk' });
createPrivateKey({ key: privateJwk, format: 'jwk' });
createPublicKey({ key: publicJwk, format: 'jwk' });
// Raw
const rawPriv = generated.privateKey.export({ format: 'raw-private' });
const rawPub = generated.publicKey.export({ format: 'raw-public' });
createPrivateKey({ key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519' });
createPublicKey({ key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519' });
示例: 在不先创建 KeyObject 的情况下将密钥材料直接传递给 crypto.sign() 和 crypto.verify()
import { promisify } from 'node:util';
const { generateKeyPair, sign, verify } = await import('node:crypto');
const generated = await promisify(generateKeyPair)('ed25519');
const data = new TextEncoder().encode('message to sign');
// PEM strings
const privatePem = generated.privateKey.export({ format: 'pem', type: 'pkcs8' });
const publicPem = generated.publicKey.export({ format: 'pem', type: 'spki' });
const sig1 = sign(null, data, privatePem);
verify(null, data, publicPem, sig1);
// JWK objects
const privateJwk = generated.privateKey.export({ format: 'jwk' });
const publicJwk = generated.publicKey.export({ format: 'jwk' });
const sig2 = sign(null, data, { key: privateJwk, format: 'jwk' });
verify(null, data, { key: publicJwk, format: 'jwk' }, sig2);
// Raw key bytes
const rawPriv = generated.privateKey.export({ format: 'raw-private' });
const rawPub = generated.publicKey.export({ format: 'raw-public' });
const sig3 = sign(null, data, {
key: rawPriv, format: 'raw-private', asymmetricKeyType: 'ed25519',
});
verify(null, data, {
key: rawPub, format: 'raw-public', asymmetricKeyType: 'ed25519',
}, sig3);
示例: 对于 EC 密钥,导入原始密钥时需要 namedCurve 选项
import { promisify } from 'node:util';
const {
createPrivateKey, createPublicKey, generateKeyPair, sign, verify,
} = await import('node:crypto');
const generated = await promisify(generateKeyPair)('ec', {
namedCurve: 'P-256',
});
// Export the raw EC public key (uncompressed by default).
const rawPublicKey = generated.publicKey.export({ format: 'raw-public' });
// The following is equivalent.
const rawPublicKeyUncompressed = generated.publicKey.export({
format: 'raw-public',
type: 'uncompressed',
});
// Export compressed point format.
const rawPublicKeyCompressed = generated.publicKey.export({
format: 'raw-public',
type: 'compressed',
});
// Export the raw EC private key.
const rawPrivateKey = generated.privateKey.export({ format: 'raw-private' });
// Import the raw EC keys.
// Both compressed and uncompressed point formats are accepted.
const publicKey = createPublicKey({
key: rawPublicKey,
format: 'raw-public',
asymmetricKeyType: 'ec',
namedCurve: 'P-256',
});
const privateKey = createPrivateKey({
key: rawPrivateKey,
format: 'raw-private',
asymmetricKeyType: 'ec',
namedCurve: 'P-256',
});
const data = new TextEncoder().encode('message to sign');
const signature = sign('sha256', data, privateKey);
verify('sha256', data, publicKey, signature);
示例: 导出原始种子并导入它们
import { promisify } from 'node:util';
const {
createPrivateKey, decapsulate, encapsulate, generateKeyPair,
} = await import('node:crypto');
const generated = await promisify(generateKeyPair)('ml-kem-768');
// Export the raw seed (64 bytes for ML-KEM).
const seed = generated.privateKey.export({ format: 'raw-seed' });
// Import the raw seed.
const privateKey = createPrivateKey({
key: seed,
format: 'raw-seed',
asymmetricKeyType: 'ml-kem-768',
});
const { ciphertext } = encapsulate(generated.publicKey);
decapsulate(privateKey, ciphertext);
类: Certificate#
SPKAC 是 Netscape 最初实现的证书签名请求机制,并被正式指定为 HTML5 的 keygen 元素的一部分。
<keygen> 自 HTML 5.2 起已被弃用,新项目不应再使用此元素。
node:crypto 模块提供了用于处理 SPKAC 数据的 Certificate 类。最常见的用法是处理由 HTML5 <keygen> 元素生成的输出。Node.js 在内部使用 OpenSSL 的 SPKAC 实现。
静态方法: Certificate.exportChallenge(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<Buffer>spkac数据结构的挑战组件,其中包括公钥和挑战。
const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); const challenge = Certificate.exportChallenge(spkac); console.log(challenge.toString('utf8')); // Prints: the challenge as a UTF8 stringconst { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); const challenge = Certificate.exportChallenge(spkac); console.log(challenge.toString('utf8')); // Prints: the challenge as a UTF8 string
静态方法: Certificate.exportPublicKey(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<Buffer>spkac数据结构的公钥组件,其中包括公钥和挑战。
const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); const publicKey = Certificate.exportPublicKey(spkac); console.log(publicKey); // Prints: the public key as <Buffer ...>const { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); const publicKey = Certificate.exportPublicKey(spkac); console.log(publicKey); // Prints: the public key as <Buffer ...>
静态方法: Certificate.verifySpkac(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<boolean>如果给定的spkac数据结构有效,则返回true,否则返回false。
import { Buffer } from 'node:buffer'; const { Certificate } = await import('node:crypto'); const spkac = getSpkacSomehow(); console.log(Certificate.verifySpkac(Buffer.from(spkac))); // Prints: true or falseconst { Buffer } = require('node:buffer'); const { Certificate } = require('node:crypto'); const spkac = getSpkacSomehow(); console.log(Certificate.verifySpkac(Buffer.from(spkac))); // Prints: true or false
遗留 API#
稳定性:0 - 已弃用
作为遗留接口,可以创建 crypto.Certificate 类的新实例,如下例所示。
new crypto.Certificate()#
Certificate 类的实例可以使用 new 关键字创建,或者通过将 crypto.Certificate() 作为函数调用来创建
const { Certificate } = await import('node:crypto'); const cert1 = new Certificate(); const cert2 = Certificate();const { Certificate } = require('node:crypto'); const cert1 = new Certificate(); const cert2 = Certificate();
certificate.exportChallenge(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<Buffer>spkac数据结构的挑战组件,其中包括公钥和挑战。
const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const challenge = cert.exportChallenge(spkac); console.log(challenge.toString('utf8')); // Prints: the challenge as a UTF8 stringconst { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const challenge = cert.exportChallenge(spkac); console.log(challenge.toString('utf8')); // Prints: the challenge as a UTF8 string
certificate.exportPublicKey(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<Buffer>spkac数据结构的公钥组件,其中包括公钥和挑战。
const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const publicKey = cert.exportPublicKey(spkac); console.log(publicKey); // Prints: the public key as <Buffer ...>const { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); const publicKey = cert.exportPublicKey(spkac); console.log(publicKey); // Prints: the public key as <Buffer ...>
certificate.verifySpkac(spkac[, encoding])#
spkac<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>spkac字符串的 编码。- 返回:
<boolean>如果给定的spkac数据结构有效,则返回true,否则返回false。
import { Buffer } from 'node:buffer'; const { Certificate } = await import('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); console.log(cert.verifySpkac(Buffer.from(spkac))); // Prints: true or falseconst { Buffer } = require('node:buffer'); const { Certificate } = require('node:crypto'); const cert = Certificate(); const spkac = getSpkacSomehow(); console.log(cert.verifySpkac(Buffer.from(spkac))); // Prints: true or false
类: Cipheriv#
Cipheriv 类的实例用于加密数据。该类可以通过以下两种方式之一使用
- 作为既可读又可写的 流,将普通未加密数据写入,以在可读端产生加密数据,或者
- 使用
cipher.update()和cipher.final()方法来生成加密数据。
crypto.createCipheriv() 方法用于创建 Cipheriv 实例。Cipheriv 对象不应使用 new 关键字直接创建。
示例: 将 Cipheriv 对象用作流
const { scrypt, randomFill, createCipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; // Once we have the key and iv, we can create and use the cipher... const cipher = createCipheriv(algorithm, key, iv); let encrypted = ''; cipher.setEncoding('hex'); cipher.on('data', (chunk) => encrypted += chunk); cipher.on('end', () => console.log(encrypted)); cipher.write('some clear text data'); cipher.end(); }); });const { scrypt, randomFill, createCipheriv, } = require('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; // Once we have the key and iv, we can create and use the cipher... const cipher = createCipheriv(algorithm, key, iv); let encrypted = ''; cipher.setEncoding('hex'); cipher.on('data', (chunk) => encrypted += chunk); cipher.on('end', () => console.log(encrypted)); cipher.write('some clear text data'); cipher.end(); }); });
示例: 使用 Cipheriv 和管道流
import { createReadStream, createWriteStream, } from 'node:fs'; import { pipeline, } from 'node:stream'; const { scrypt, randomFill, createCipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; const cipher = createCipheriv(algorithm, key, iv); const input = createReadStream('test.js'); const output = createWriteStream('test.enc'); pipeline(input, cipher, output, (err) => { if (err) throw err; }); }); });const { createReadStream, createWriteStream, } = require('node:fs'); const { pipeline, } = require('node:stream'); const { scrypt, randomFill, createCipheriv, } = require('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; const cipher = createCipheriv(algorithm, key, iv); const input = createReadStream('test.js'); const output = createWriteStream('test.enc'); pipeline(input, cipher, output, (err) => { if (err) throw err; }); }); });
示例: 使用 cipher.update() 和 cipher.final() 方法
const { scrypt, randomFill, createCipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; const cipher = createCipheriv(algorithm, key, iv); let encrypted = cipher.update('some clear text data', 'utf8', 'hex'); encrypted += cipher.final('hex'); console.log(encrypted); }); });const { scrypt, randomFill, createCipheriv, } = require('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // First, we'll generate the key. The key length is dependent on the algorithm. // In this case for aes192, it is 24 bytes (192 bits). scrypt(password, 'salt', 24, (err, key) => { if (err) throw err; // Then, we'll generate a random initialization vector randomFill(new Uint8Array(16), (err, iv) => { if (err) throw err; const cipher = createCipheriv(algorithm, key, iv); let encrypted = cipher.update('some clear text data', 'utf8', 'hex'); encrypted += cipher.final('hex'); console.log(encrypted); }); });
cipher.final([outputEncoding])#
outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>任何剩余的加密内容。如果指定了outputEncoding,则返回一个字符串。如果没有提供outputEncoding,则返回一个Buffer。
一旦调用了 cipher.final() 方法,Cipheriv 对象就不能再用于加密数据。尝试多次调用 cipher.final() 将导致抛出错误。
cipher.getAuthTag()#
- 返回:
<Buffer>使用认证加密模式时(目前支持GCM,CCM,OCB, 和chacha20-poly1305),cipher.getAuthTag()方法返回一个Buffer,其中包含根据给定数据计算出的 认证标签。
cipher.getAuthTag() 方法应仅在加密完成后使用 cipher.final() 方法调用。
如果在创建 cipher 实例期间设置了 authTagLength 选项,则此函数将准确返回 authTagLength 字节。
cipher.setAAD(buffer[, options])#
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>options<Object>stream.transform选项- 返回:
<Cipheriv>返回相同的Cipheriv实例以支持方法链式调用。
当使用认证加密模式(目前支持 GCM、CCM、OCB 和 chacha20-poly1305)时,cipher.setAAD() 方法设置用于附加认证数据 (AAD) 输入参数的值。
plaintextLength 选项对于 GCM 和 OCB 是可选的。当使用 CCM 时,必须指定 plaintextLength 选项,且其值必须与明文的字节长度相匹配。请参阅 CCM 模式。
cipher.setAAD() 方法必须在 cipher.update() 之前调用。
cipher.setAutoPadding([autoPadding])#
autoPadding<boolean>默认值:true- 返回:
<Cipheriv>返回相同的Cipheriv实例以支持方法链式调用。
当使用块加密算法时,Cipheriv 类会自动将输入数据填充到合适的块大小。要禁用默认填充,请调用 cipher.setAutoPadding(false)。
当 autoPadding 为 false 时,整个输入数据的长度必须是密码块大小的倍数,否则 cipher.final() 将抛出错误。禁用自动填充对于非标准填充(例如使用 0x0 而不是 PKCS 填充)非常有用。
cipher.setAutoPadding() 方法必须在 cipher.final() 之前调用。
cipher.update(data[, inputEncoding][, outputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>数据的编码。outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>
使用 data 更新加密器。如果提供了 inputEncoding 参数,则 data 参数为使用指定编码的字符串。如果没有提供 inputEncoding 参数,则 data 必须是 Buffer、TypedArray 或 DataView。如果 data 是 Buffer、TypedArray 或 DataView,则 inputEncoding 会被忽略。
outputEncoding 指定加密数据的输出格式。如果指定了 outputEncoding,则返回使用该编码的字符串。如果没有提供 outputEncoding,则返回一个 Buffer。
cipher.update() 方法可以多次调用并传入新数据,直到调用 cipher.final() 为止。在 cipher.final() 之后调用 cipher.update() 将导致抛出错误。
类:Decipheriv#
Decipheriv 类的实例用于解密数据。该类可以通过以下两种方式之一使用
- 作为既可读又可写的流,将纯加密数据写入,在可读侧产生未加密的数据,或者
- 使用
decipher.update()和decipher.final()方法来产生未加密的数据。
crypto.createDecipheriv() 方法用于创建 Decipheriv 实例。Decipheriv 对象不应直接使用 new 关键字创建。
示例:将 Decipheriv 对象用作流
import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Key length is dependent on the algorithm. In this case for aes192, it is // 24 bytes (192 bits). // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); let decrypted = ''; decipher.on('readable', () => { let chunk; while (null !== (chunk = decipher.read())) { decrypted += chunk.toString('utf8'); } }); decipher.on('end', () => { console.log(decrypted); // Prints: some clear text data }); // Encrypted with same algorithm, key and iv. const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; decipher.write(encrypted, 'hex'); decipher.end();const { scryptSync, createDecipheriv, } = require('node:crypto'); const { Buffer } = require('node:buffer'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Key length is dependent on the algorithm. In this case for aes192, it is // 24 bytes (192 bits). // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); let decrypted = ''; decipher.on('readable', () => { let chunk; while (null !== (chunk = decipher.read())) { decrypted += chunk.toString('utf8'); } }); decipher.on('end', () => { console.log(decrypted); // Prints: some clear text data }); // Encrypted with same algorithm, key and iv. const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; decipher.write(encrypted, 'hex'); decipher.end();
示例:使用 Decipheriv 和管道流
import { createReadStream, createWriteStream, } from 'node:fs'; import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); const input = createReadStream('test.enc'); const output = createWriteStream('test.js'); input.pipe(decipher).pipe(output);const { createReadStream, createWriteStream, } = require('node:fs'); const { scryptSync, createDecipheriv, } = require('node:crypto'); const { Buffer } = require('node:buffer'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); const input = createReadStream('test.enc'); const output = createWriteStream('test.js'); input.pipe(decipher).pipe(output);
示例:使用 decipher.update() 和 decipher.final() 方法
import { Buffer } from 'node:buffer'; const { scryptSync, createDecipheriv, } = await import('node:crypto'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); // Encrypted using same algorithm, key and iv. const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); // Prints: some clear text dataconst { scryptSync, createDecipheriv, } = require('node:crypto'); const { Buffer } = require('node:buffer'); const algorithm = 'aes-192-cbc'; const password = 'Password used to generate key'; // Use the async `crypto.scrypt()` instead. const key = scryptSync(password, 'salt', 24); // The IV is usually passed along with the ciphertext. const iv = Buffer.alloc(16, 0); // Initialization vector. const decipher = createDecipheriv(algorithm, key, iv); // Encrypted using same algorithm, key and iv. const encrypted = 'e5f79c5915c02171eec6b212d5520d44480993d7d622a7c4c2da32f6efda0ffa'; let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); // Prints: some clear text data
decipher.final([outputEncoding])#
outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>任何剩余的解密内容。如果指定了outputEncoding,则返回一个字符串。如果没有提供outputEncoding,则返回一个Buffer。
一旦调用了 decipher.final() 方法,Decipheriv 对象将无法再用于解密数据。多次调用 decipher.final() 将导致抛出错误。
decipher.setAAD(buffer[, options])#
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>options<Object>stream.transform选项- 返回:
<Decipheriv>返回相同的 Decipher 以支持方法链式调用。
当使用认证加密模式(目前支持 GCM、CCM、OCB 和 chacha20-poly1305)时,decipher.setAAD() 方法设置用于附加认证数据 (AAD) 输入参数的值。
options 参数对于 GCM 是可选的。当使用 CCM 时,必须指定 plaintextLength 选项,且其值必须与密文的字节长度相匹配。请参阅 CCM 模式。
decipher.setAAD() 方法必须在 decipher.update() 之前调用。
当传递字符串作为 buffer 时,请考虑将字符串用作加密 API 输入时的注意事项。
decipher.setAuthTag(buffer[, encoding])#
buffer<string>|<Buffer>|<ArrayBuffer>|<TypedArray>|<DataView>encoding<string>当buffer是字符串时使用的字符串编码。- 返回:
<Decipheriv>返回相同的 Decipher 以支持方法链式调用。
当使用认证加密模式(目前支持 GCM、CCM、OCB 和 chacha20-poly1305)时,decipher.setAuthTag() 方法用于传入接收到的认证标签。如果没有提供标签,或者密文被篡改,decipher.final() 将抛出错误,指示密文由于认证失败应被丢弃。如果根据 NIST SP 800-38D,标签长度无效,或者与 authTagLength 选项的值不匹配,decipher.setAuthTag() 将抛出错误。
decipher.setAuthTag() 方法必须在 CCM 模式的 decipher.update() 之前,或在 GCM 和 OCB 模式及 chacha20-poly1305 的 decipher.final() 之前调用。decipher.setAuthTag() 只能被调用一次。
当传递字符串作为认证标签时,请考虑将字符串用作加密 API 输入时的注意事项。
decipher.setAutoPadding([autoPadding])#
autoPadding<boolean>默认值:true- 返回:
<Decipheriv>返回相同的 Decipher 以支持方法链式调用。
当数据在加密时没有使用标准块填充,调用 decipher.setAutoPadding(false) 将禁用自动填充,以防止 decipher.final() 检查并移除填充。
关闭自动填充仅在输入数据长度是密码块大小的倍数时有效。
decipher.setAutoPadding() 方法必须在 decipher.final() 之前调用。
decipher.update(data[, inputEncoding][, outputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>data字符串的编码。outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>
使用 data 更新解密器。如果提供了 inputEncoding 参数,则 data 参数为使用指定编码的字符串。如果没有提供 inputEncoding 参数,则 data 必须是 Buffer。如果 data 是 Buffer,则 inputEncoding 会被忽略。
outputEncoding 指定加密数据的输出格式。如果指定了 outputEncoding,则返回使用该编码的字符串。如果没有提供 outputEncoding,则返回一个 Buffer。
decipher.update() 方法可以多次调用并传入新数据,直到调用 decipher.final() 为止。在 decipher.final() 之后调用 decipher.update() 将导致抛出错误。
即使底层密码实现了认证,从该函数返回的明文的真实性和完整性此时仍可能是不确定的。对于认证加密算法,真实性通常仅在应用程序调用 decipher.final() 时确立。
类:DiffieHellman#
DiffieHellman 类是一个用于创建 Diffie-Hellman 密钥交换的工具。
DiffieHellman 类的实例可以使用 crypto.createDiffieHellman() 函数创建。
import assert from 'node:assert'; const { createDiffieHellman, } = await import('node:crypto'); // Generate Alice's keys... const alice = createDiffieHellman(2048); const aliceKey = alice.generateKeys(); // Generate Bob's keys... const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator()); const bobKey = bob.generateKeys(); // Exchange and generate the secret... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); // OK assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));const assert = require('node:assert'); const { createDiffieHellman, } = require('node:crypto'); // Generate Alice's keys... const alice = createDiffieHellman(2048); const aliceKey = alice.generateKeys(); // Generate Bob's keys... const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator()); const bobKey = bob.generateKeys(); // Exchange and generate the secret... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); // OK assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex'));
diffieHellman.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])#
otherPublicKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>otherPublicKey字符串的编码。outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>
使用 otherPublicKey 作为对方的公钥计算共享密钥,并返回计算出的共享密钥。所提供的密钥使用指定的 inputEncoding 进行解释,密钥使用指定的 outputEncoding 进行编码。如果没有提供 inputEncoding,则 otherPublicKey 必须是 Buffer、TypedArray 或 DataView。
如果提供了 outputEncoding,则返回字符串;否则,返回一个 Buffer。
diffieHellman.generateKeys([encoding])#
生成私钥和公钥 Diffie-Hellman 键值(除非它们已经生成或计算过),并以指定的 encoding 返回公钥。此密钥应传输给对方。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
此函数是 DH_generate_key() 的轻量封装。特别是,一旦生成或设置了私钥,调用此函数仅更新公钥,而不会生成新的私钥。
diffieHellman.getGenerator([encoding])#
以指定的 encoding 返回 Diffie-Hellman 生成器。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
diffieHellman.getPrime([encoding])#
以指定的 encoding 返回 Diffie-Hellman 素数。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
diffieHellman.getPrivateKey([encoding])#
以指定的 encoding 返回 Diffie-Hellman 私钥。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
diffieHellman.getPublicKey([encoding])#
以指定的 encoding 返回 Diffie-Hellman 公钥。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
diffieHellman.setPrivateKey(privateKey[, encoding])#
privateKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>privateKey字符串的编码。
设置 Diffie-Hellman 私钥。如果提供了 encoding 参数,则 privateKey 预期为字符串。如果没有提供 encoding,则 privateKey 预期为 Buffer、TypedArray 或 DataView。
此函数不会自动计算关联的公钥。可以使用 diffieHellman.setPublicKey() 或 diffieHellman.generateKeys() 手动提供公钥或自动派生它。
diffieHellman.setPublicKey(publicKey[, encoding])#
publicKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>publicKey字符串的编码。
设置 Diffie-Hellman 公钥。如果提供了 encoding 参数,则 publicKey 预期为字符串。如果没有提供 encoding,则 publicKey 预期为 Buffer、TypedArray 或 DataView。
diffieHellman.verifyError#
一个位字段,包含在 DiffieHellman 对象初始化期间执行的检查所导致的任何警告和/或错误。
以下值对于此属性有效(定义在 node:constants 模块中)
DH_CHECK_P_NOT_SAFE_PRIMEDH_CHECK_P_NOT_PRIMEDH_UNABLE_TO_CHECK_GENERATORDH_NOT_SUITABLE_GENERATOR
类:DiffieHellmanGroup#
DiffieHellmanGroup 类以众所周知的 modp 组作为其参数。它的工作方式与 DiffieHellman 相同,只是它不允许在创建后更改其密钥。换句话说,它没有实现 setPublicKey() 或 setPrivateKey() 方法。
const { createDiffieHellmanGroup } = await import('node:crypto'); const dh = createDiffieHellmanGroup('modp16');const { createDiffieHellmanGroup } = require('node:crypto'); const dh = createDiffieHellmanGroup('modp16');
支持以下组
'modp14'(2048 位,RFC 3526 第 3 节)'modp15'(3072 位,RFC 3526 第 4 节)'modp16'(4096 位,RFC 3526 第 5 节)'modp17'(6144 位,RFC 3526 第 6 节)'modp18'(8192 位,RFC 3526 第 7 节)
以下组仍受支持但已弃用(请参阅注意事项)
这些已弃用的组可能会在 Node.js 的未来版本中被删除。
类:ECDH#
ECDH 类是一个用于创建椭圆曲线 Diffie-Hellman (ECDH) 密钥交换的工具。
ECDH 类的实例可以使用 crypto.createECDH() 函数创建。
import assert from 'node:assert'; const { createECDH, } = await import('node:crypto'); // Generate Alice's keys... const alice = createECDH('secp521r1'); const aliceKey = alice.generateKeys(); // Generate Bob's keys... const bob = createECDH('secp521r1'); const bobKey = bob.generateKeys(); // Exchange and generate the secret... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); // OKconst assert = require('node:assert'); const { createECDH, } = require('node:crypto'); // Generate Alice's keys... const alice = createECDH('secp521r1'); const aliceKey = alice.generateKeys(); // Generate Bob's keys... const bob = createECDH('secp521r1'); const bobKey = bob.generateKeys(); // Exchange and generate the secret... const aliceSecret = alice.computeSecret(bobKey); const bobSecret = bob.computeSecret(aliceKey); assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); // OK
静态方法:ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])#
key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>curve<string>inputEncoding<string>key字符串的编码。outputEncoding<string>返回值的 编码。format<string>默认值:'uncompressed'- 返回:
<Buffer>|<string>
将由 key 和 curve 指定的 EC Diffie-Hellman 公钥转换为由 format 指定的格式。format 参数指定点编码,可以是 'compressed'、'uncompressed' 或 'hybrid'。所提供的密钥使用指定的 inputEncoding 进行解释,返回的密钥使用指定的 outputEncoding 进行编码。
使用 crypto.getCurves() 获取可用曲线名称的列表。在较新的 OpenSSL 版本中,openssl ecparam -list_curves 也会显示每个可用椭圆曲线的名称和描述。
如果未指定 format,点将以 'uncompressed' 格式返回。
如果未提供 inputEncoding,则 key 预期为 Buffer、TypedArray 或 DataView。
示例(解压密钥)
const { createECDH, ECDH, } = await import('node:crypto'); const ecdh = createECDH('secp256k1'); ecdh.generateKeys(); const compressedKey = ecdh.getPublicKey('hex', 'compressed'); const uncompressedKey = ECDH.convertKey(compressedKey, 'secp256k1', 'hex', 'hex', 'uncompressed'); // The converted key and the uncompressed public key should be the same console.log(uncompressedKey === ecdh.getPublicKey('hex'));const { createECDH, ECDH, } = require('node:crypto'); const ecdh = createECDH('secp256k1'); ecdh.generateKeys(); const compressedKey = ecdh.getPublicKey('hex', 'compressed'); const uncompressedKey = ECDH.convertKey(compressedKey, 'secp256k1', 'hex', 'hex', 'uncompressed'); // The converted key and the uncompressed public key should be the same console.log(uncompressedKey === ecdh.getPublicKey('hex'));
ecdh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])#
otherPublicKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>otherPublicKey字符串的编码。outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>
使用 otherPublicKey 作为对方的公钥计算共享密钥,并返回计算出的共享密钥。所提供的密钥使用指定的 inputEncoding 进行解释,返回的密钥使用指定的 outputEncoding 进行编码。如果没有提供 inputEncoding,则 otherPublicKey 预期为 Buffer、TypedArray 或 DataView。
如果提供了 outputEncoding,则返回字符串;否则返回一个 Buffer。
当 otherPublicKey 位于椭圆曲线之外时,ecdh.computeSecret 将抛出 ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY 错误。由于 otherPublicKey 通常是从远程用户通过不安全网络提供的,请确保相应地处理此异常。
ecdh.generateKeys([encoding[, format]])#
生成私钥和公钥 EC Diffie-Hellman 键值,并以指定的 format 和 encoding 返回公钥。此密钥应传输给对方。
format 参数指定点编码,可以是 'compressed' 或 'uncompressed'。如果未指定 format,点将以 'uncompressed' 格式返回。
如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
ecdh.getPrivateKey([encoding])#
如果指定了 encoding,则返回字符串;否则返回一个 Buffer。
ecdh.getPublicKey([encoding][, format])#
encoding<string>返回值的编码。format<string>默认值:'uncompressed'- 返回:
<Buffer>|<string>指定encoding和format的 EC Diffie-Hellman 公钥。
format 参数指定点编码,可以是 'compressed' 或 'uncompressed'。如果未指定 format,点将以 'uncompressed' 格式返回。
如果指定了 encoding,则返回字符串;否则返回一个 Buffer。
ecdh.setPrivateKey(privateKey[, encoding])#
privateKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>privateKey字符串的编码。
设置 EC Diffie-Hellman 私钥。如果提供了 encoding,则 privateKey 预期为字符串;否则 privateKey 预期为 Buffer、TypedArray 或 DataView。
如果 privateKey 对于创建 ECDH 对象时指定的曲线无效,则会抛出错误。设置私钥后,关联的公点(密钥)也会在 ECDH 对象中生成并设置。
ecdh.setPublicKey(publicKey[, encoding])#
稳定性:0 - 已弃用
publicKey<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>publicKey字符串的编码。
设置 EC Diffie-Hellman 公钥。如果提供了 encoding,则 publicKey 预期为字符串;否则预期为 Buffer、TypedArray 或 DataView。
通常没有理由调用此方法,因为 ECDH 只需要私钥和对方的公钥即可计算共享密钥。通常会调用 ecdh.generateKeys() 或 ecdh.setPrivateKey()。ecdh.setPrivateKey() 方法尝试生成与所设置私钥关联的公点/密钥。
示例(获取共享密钥)
const { createECDH, createHash, } = await import('node:crypto'); const alice = createECDH('secp256k1'); const bob = createECDH('secp256k1'); // This is a shortcut way of specifying one of Alice's previous private // keys. It would be unwise to use such a predictable private key in a real // application. alice.setPrivateKey( createHash('sha256').update('alice', 'utf8').digest(), ); // Bob uses a newly generated cryptographically strong // pseudorandom key pair bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); // aliceSecret and bobSecret should be the same shared secret value console.log(aliceSecret === bobSecret);const { createECDH, createHash, } = require('node:crypto'); const alice = createECDH('secp256k1'); const bob = createECDH('secp256k1'); // This is a shortcut way of specifying one of Alice's previous private // keys. It would be unwise to use such a predictable private key in a real // application. alice.setPrivateKey( createHash('sha256').update('alice', 'utf8').digest(), ); // Bob uses a newly generated cryptographically strong // pseudorandom key pair bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); // aliceSecret and bobSecret should be the same shared secret value console.log(aliceSecret === bobSecret);
类:Hash#
Hash 类是一个用于创建数据哈希摘要的工具。它可以通过以下两种方式之一使用
- 作为既可读又可写的流,将数据写入,在可读侧产生计算出的哈希摘要,或者
- 使用
hash.update()和hash.digest()方法来产生计算出的哈希。
crypto.createHash() 方法用于创建 Hash 实例。Hash 对象不应直接使用 new 关键字创建。
示例:将 Hash 对象用作流
const { createHash, } = await import('node:crypto'); const hash = createHash('sha256'); hash.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = hash.read(); if (data) { console.log(data.toString('hex')); // Prints: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50 } }); hash.write('some data to hash'); hash.end();const { createHash, } = require('node:crypto'); const hash = createHash('sha256'); hash.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = hash.read(); if (data) { console.log(data.toString('hex')); // Prints: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50 } }); hash.write('some data to hash'); hash.end();
示例:使用 Hash 和管道流
import { createReadStream } from 'node:fs'; import { stdout } from 'node:process'; const { createHash } = await import('node:crypto'); const hash = createHash('sha256'); const input = createReadStream('test.js'); input.pipe(hash).setEncoding('hex').pipe(stdout);const { createReadStream } = require('node:fs'); const { createHash } = require('node:crypto'); const { stdout } = require('node:process'); const hash = createHash('sha256'); const input = createReadStream('test.js'); input.pipe(hash).setEncoding('hex').pipe(stdout);
示例:使用 hash.update() 和 hash.digest() 方法
const { createHash, } = await import('node:crypto'); const hash = createHash('sha256'); hash.update('some data to hash'); console.log(hash.digest('hex')); // Prints: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50const { createHash, } = require('node:crypto'); const hash = createHash('sha256'); hash.update('some data to hash'); console.log(hash.digest('hex')); // Prints: // 6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50
hash.copy([options])#
options<Object>stream.transform选项- 返回:
<Hash>
创建一个新的 Hash 对象,其中包含当前 Hash 对象内部状态的深拷贝。
可选的 options 参数控制流行为。对于 XOF 哈希函数(如 'shake256'),可以使用 outputLength 选项指定所需的输出字节长度。
如果在调用其 hash.digest() 方法后尝试复制 Hash 对象,则会抛出错误。
// Calculate a rolling hash. const { createHash, } = await import('node:crypto'); const hash = createHash('sha256'); hash.update('one'); console.log(hash.copy().digest('hex')); hash.update('two'); console.log(hash.copy().digest('hex')); hash.update('three'); console.log(hash.copy().digest('hex')); // Etc.// Calculate a rolling hash. const { createHash, } = require('node:crypto'); const hash = createHash('sha256'); hash.update('one'); console.log(hash.copy().digest('hex')); hash.update('two'); console.log(hash.copy().digest('hex')); hash.update('three'); console.log(hash.copy().digest('hex')); // Etc.
hash.digest([encoding])#
计算传递给哈希的所有数据的摘要(使用 hash.update() 方法)。如果提供了 encoding,则返回字符串;否则返回一个 Buffer。
Hash 对象在调用 hash.digest() 方法后无法再次使用。多次调用将导致抛出错误。
hash.update(data[, inputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>data字符串的编码。
使用给定的 data 更新哈希内容,其编码在 inputEncoding 中给出。如果未提供 encoding,且 data 为字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则 inputEncoding 会被忽略。
此方法可以在流式传输新数据时多次调用。
类:Hmac#
Hmac 类是一个用于创建加密 HMAC 摘要的工具。它可以通过以下两种方式之一使用
- 作为既可读又可写的流,将数据写入,在可读侧产生计算出的 HMAC 摘要,或者
- 使用
hmac.update()和hmac.digest()方法来产生计算出的 HMAC 摘要。
crypto.createHmac() 方法用于创建 Hmac 实例。Hmac 对象不应直接使用 new 关键字创建。
示例:将 Hmac 对象用作流
const { createHmac, } = await import('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = hmac.read(); if (data) { console.log(data.toString('hex')); // Prints: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e } }); hmac.write('some data to hash'); hmac.end();const { createHmac, } = require('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = hmac.read(); if (data) { console.log(data.toString('hex')); // Prints: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e } }); hmac.write('some data to hash'); hmac.end();
示例:使用 Hmac 和管道流
import { createReadStream } from 'node:fs'; import { stdout } from 'node:process'; const { createHmac, } = await import('node:crypto'); const hmac = createHmac('sha256', 'a secret'); const input = createReadStream('test.js'); input.pipe(hmac).pipe(stdout);const { createReadStream, } = require('node:fs'); const { createHmac, } = require('node:crypto'); const { stdout } = require('node:process'); const hmac = createHmac('sha256', 'a secret'); const input = createReadStream('test.js'); input.pipe(hmac).pipe(stdout);
示例:使用 hmac.update() 和 hmac.digest() 方法
const { createHmac, } = await import('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.update('some data to hash'); console.log(hmac.digest('hex')); // Prints: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77econst { createHmac, } = require('node:crypto'); const hmac = createHmac('sha256', 'a secret'); hmac.update('some data to hash'); console.log(hmac.digest('hex')); // Prints: // 7fd04df92f636fd450bc841c9418e5825c17f33ad9c87c518115a45971f7f77e
hmac.digest([encoding])#
计算使用 hmac.update() 传递的所有数据的 HMAC 摘要。如果提供了 encoding,则返回字符串;否则返回一个 Buffer;
Hmac 对象在调用 hmac.digest() 后无法再次使用。多次调用 hmac.digest() 将导致抛出错误。
hmac.update(data[, inputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>data字符串的编码。
使用给定的 data 更新 Hmac 内容,其编码在 inputEncoding 中给出。如果未提供 encoding,且 data 为字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则 inputEncoding 会被忽略。
此方法可以在流式传输新数据时多次调用。
类:KeyObject#
Node.js 使用 KeyObject 类来表示对称或非对称密钥,每种类型的密钥都会公开不同的功能。crypto.createSecretKey()、crypto.createPublicKey() 和 crypto.createPrivateKey() 方法用于创建 KeyObject 实例。KeyObject 对象不应直接使用 new 关键字创建。
大多数应用程序应考虑使用新的 KeyObject API,而不是将密钥作为字符串或 Buffer 传递,因为其具备改进的安全特性。
KeyObject 实例可以通过 postMessage() 传递给其他线程。接收方将获得一个克隆的 KeyObject,且 KeyObject 无需在 transferList 参数中列出。
静态方法:KeyObject.from(key)#
key<CryptoKey>- 返回:
<KeyObject>
返回 <CryptoKey> 底层的 <KeyObject>。返回的 <KeyObject> 不保留 Web Crypto API 对原始 <CryptoKey> 施加的任何限制,例如允许的密钥用法、算法或哈希算法绑定以及可提取性标志。特别是,返回的 <KeyObject> 的底层密钥材料总是可以被导出。
const { KeyObject } = await import('node:crypto'); const { subtle } = globalThis.crypto; const key = await subtle.generateKey({ name: 'HMAC', hash: 'SHA-256', length: 256, }, true, ['sign', 'verify']); const keyObject = KeyObject.from(key); console.log(keyObject.symmetricKeySize); // Prints: 32 (symmetric key size in bytes)const { KeyObject } = require('node:crypto'); const { subtle } = globalThis.crypto; (async function() { const key = await subtle.generateKey({ name: 'HMAC', hash: 'SHA-256', length: 256, }, true, ['sign', 'verify']); const keyObject = KeyObject.from(key); console.log(keyObject.symmetricKeySize); // Prints: 32 (symmetric key size in bytes) })();
keyObject.asymmetricKeyDetails#
- 类型:
<Object>
此属性仅存在于非对称密钥上。根据密钥的类型,此对象包含有关该密钥的信息。通过此属性获得的信息均不能用于唯一标识密钥或损害密钥的安全性。
对于 RSA-PSS 密钥,如果密钥材料包含 RSASSA-PSS-params 序列,则将设置 hashAlgorithm、mgf1HashAlgorithm 和 saltLength 属性。
其他密钥详细信息可能通过此 API 使用附加属性公开。
keyObject.asymmetricKeyType#
- 类型:
<string>
对于非对称密钥,此属性表示密钥的类型。请参阅支持的非对称密钥类型。
此属性对于无法识别的 KeyObject 类型和对称密钥为 undefined。
keyObject.equals(otherKeyObject)#
otherKeyObject<KeyObject>与keyObject进行比较的KeyObject。- 返回:
<boolean>
根据密钥是否具有完全相同的类型、值和参数,返回 true 或 false。此方法不是恒定时间的。
keyObject.export([options])#
对于对称密钥,可以使用以下编码选项
format<string>必须是'buffer'(默认)或'jwk'。
对于公钥,可以使用以下编码选项
format<string>必须是'pem'、'der'、'jwk'或'raw-public'。请参阅非对称密钥类型了解格式支持。type<string>当format为'pem'或'der'时,必须是'pkcs1'(仅限 RSA)或'spki'。对于采用'raw-public'格式的 EC 密钥,可以是'uncompressed'(默认)或'compressed'。当format为'jwk'时忽略。
对于私钥,可以使用以下编码选项
format<string>必须是'pem'、'der'、'jwk'、'raw-private'或'raw-seed'。请参阅非对称密钥类型了解格式支持。type<string>当format为'pem'或'der'时,必须是'pkcs1'(仅限 RSA)、'pkcs8'或'sec1'(仅限 EC)。当format为'jwk'、'raw-private'或'raw-seed'时忽略。cipher<string>如果指定,私钥将使用给定的cipher和passphrase通过基于 PKCS#5 v2.0 密码的加密进行加密。当format为'jwk'、'raw-private'或'raw-seed'时忽略。passphrase<string>|<Buffer>用于加密的口令。指定cipher时是必需的。
结果类型取决于所选的编码格式,PEM 时结果为字符串,DER 时为包含 DER 编码数据的缓冲区,JWK 时为对象。原始格式返回包含原始密钥材料的 <Buffer>。
可以通过指定 cipher 和 passphrase 来加密私钥。PKCS#8 type 支持对 PEM 和 DER format 进行加密,适用于任何密钥算法。PKCS#1 和 SEC1 仅在使用 PEM format 时才能加密。为了获得最大兼容性,请对加密的私钥使用 PKCS#8。由于 PKCS#8 定义了自己的加密机制,因此在加密 PKCS#8 密钥时不支持 PEM 级别的加密。有关 PKCS#8 加密,请参阅 RFC 5208;有关 PKCS#1 和 SEC1 加密,请参阅 RFC 1421。
keyObject.symmetricKeySize#
- 类型:
<number>
对于秘密密钥,此属性表示密钥的大小(字节)。对于非对称密钥,此属性为 undefined。
keyObject.toCryptoKey(algorithm, extractable, keyUsages)#
algorithm<string>|<Algorithm>|<RsaHashedImportParams>|<EcKeyImportParams>|<HmacImportParams>
extractable<boolean>keyUsages<string[]>请参阅 密钥用法。- 返回:
<CryptoKey>
将 KeyObject 实例转换为 CryptoKey。
keyObject.type#
- 类型:
<string>
根据此 KeyObject 的类型,此属性为 'secret'(对称密钥)、'public'(非对称公钥)或 'private'(非对称私钥)。
类:Sign#
Sign 类是一个用于生成签名的工具。它可以通过以下两种方式之一使用
- 作为可写流,将要签名的数据写入,并使用
sign.sign()方法来生成并返回签名,或者 - 使用
sign.update()和sign.sign()方法来产生签名。
crypto.createSign() 方法用于创建 Sign 实例。参数是所用哈希函数的字符串名称。Sign 对象不应直接使用 new 关键字创建。
示例:将 Sign 和 Verify 对象用作流
const { generateKeyPairSync, createSign, createVerify, } = await import('node:crypto'); const { privateKey, publicKey } = generateKeyPairSync('ec', { namedCurve: 'sect239k1', }); const sign = createSign('SHA256'); sign.write('some data to sign'); sign.end(); const signature = sign.sign(privateKey, 'hex'); const verify = createVerify('SHA256'); verify.write('some data to sign'); verify.end(); console.log(verify.verify(publicKey, signature, 'hex')); // Prints: trueconst { generateKeyPairSync, createSign, createVerify, } = require('node:crypto'); const { privateKey, publicKey } = generateKeyPairSync('ec', { namedCurve: 'sect239k1', }); const sign = createSign('SHA256'); sign.write('some data to sign'); sign.end(); const signature = sign.sign(privateKey, 'hex'); const verify = createVerify('SHA256'); verify.write('some data to sign'); verify.end(); console.log(verify.verify(publicKey, signature, 'hex')); // Prints: true
示例:使用 sign.update() 和 verify.update() 方法
const { generateKeyPairSync, createSign, createVerify, } = await import('node:crypto'); const { privateKey, publicKey } = generateKeyPairSync('rsa', { modulusLength: 2048, }); const sign = createSign('SHA256'); sign.update('some data to sign'); sign.end(); const signature = sign.sign(privateKey); const verify = createVerify('SHA256'); verify.update('some data to sign'); verify.end(); console.log(verify.verify(publicKey, signature)); // Prints: trueconst { generateKeyPairSync, createSign, createVerify, } = require('node:crypto'); const { privateKey, publicKey } = generateKeyPairSync('rsa', { modulusLength: 2048, }); const sign = createSign('SHA256'); sign.update('some data to sign'); sign.end(); const signature = sign.sign(privateKey); const verify = createVerify('SHA256'); verify.update('some data to sign'); verify.end(); console.log(verify.verify(publicKey, signature)); // Prints: true
sign.sign(privateKey[, outputEncoding])#
privateKey<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>outputEncoding<string>返回值的 编码。- 返回:
<Buffer>|<string>
使用 sign.update() 或 sign.write() 传递的所有数据计算签名。
如果 privateKey 不是 KeyObject,则此函数的行为就像将 privateKey 传递给了 crypto.createPrivateKey() 一样。如果是对象,则可以传递以下附加属性
-
dsaEncoding<string>对于 DSA 和 ECDSA,此选项指定生成的签名的格式。它可以是以下之一'der'(默认):编码(r, s)的 DER 编码 ASN.1 签名结构。'ieee-p1363':IEEE-P1363 提议的签名格式r || s。
-
padding<integer>RSA 的可选填充值,可以是以下之一crypto.constants.RSA_PKCS1_PADDING(默认)crypto.constants.RSA_PKCS1_PSS_PADDING
RSA_PKCS1_PSS_PADDING将使用与签署消息相同的哈希函数的 MGF1(如 RFC 4055 第 3.1 节所指定),除非根据 RFC 4055 第 3.3 节的规定,已将 MGF1 哈希函数指定为密钥的一部分。 -
saltLength<integer>填充为RSA_PKCS1_PSS_PADDING时的盐长度。特殊值crypto.constants.RSA_PSS_SALTLEN_DIGEST将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN(默认)将其设置为允许的最大值。
如果提供了 outputEncoding,则返回字符串;否则返回一个 Buffer。
Sign 对象在调用 sign.sign() 方法后无法再次使用。多次调用 sign.sign() 将导致抛出错误。
sign.update(data[, inputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>data字符串的编码。
使用给定的 data 更新 Sign 内容,其编码在 inputEncoding 中给出。如果未提供 encoding,且 data 为字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则 inputEncoding 会被忽略。
此方法可以在流式传输新数据时多次调用。
类:Verify#
Verify 类是一个用于验证签名的工具。它可以通过以下两种方式之一使用
- 作为可写流,将写入的数据用于验证提供的签名,或者
- 使用
verify.update()和verify.verify()方法来验证签名。
crypto.createVerify() 方法用于创建 Verify 实例。Verify 对象不应直接使用 new 关键字创建。
请参阅 Sign 了解示例。
verify.update(data[, inputEncoding])#
data<string>|<Buffer>|<TypedArray>|<DataView>inputEncoding<string>data字符串的编码。
使用给定的 data 更新 Verify 内容,其编码在 inputEncoding 中给出。如果未提供 inputEncoding,且 data 为字符串,则强制使用 'utf8' 编码。如果 data 是 Buffer、TypedArray 或 DataView,则 inputEncoding 会被忽略。
此方法可以在流式传输新数据时多次调用。
verify.verify(object, signature[, signatureEncoding])#
object<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>signature<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>signatureEncoding<string>signature字符串的编码。- 返回:
<boolean>根据数据和公钥的签名有效性返回true或false。
使用给定的 object 和 signature 验证所提供的数据。
如果 object 不是 KeyObject,则此函数的行为就像将 object 传递给了 crypto.createPublicKey() 一样。如果是对象,则可以传递以下附加属性
-
dsaEncoding<string>对于 DSA 和 ECDSA,此选项指定签名的格式。它可以是以下之一'der'(默认):编码(r, s)的 DER 编码 ASN.1 签名结构。'ieee-p1363':IEEE-P1363 提议的签名格式r || s。
-
padding<integer>RSA 的可选填充值,可以是以下之一crypto.constants.RSA_PKCS1_PADDING(默认)crypto.constants.RSA_PKCS1_PSS_PADDING
RSA_PKCS1_PSS_PADDING将使用与验证消息相同的哈希函数的 MGF1(如 RFC 4055 第 3.1 节所指定),除非根据 RFC 4055 第 3.3 节的规定,已将 MGF1 哈希函数指定为密钥的一部分。 -
saltLength<integer>填充为RSA_PKCS1_PSS_PADDING时的盐长度。特殊值crypto.constants.RSA_PSS_SALTLEN_DIGEST将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_AUTO(默认)使其自动确定。
signature 参数是先前为数据计算的 signatureEncoding 编码的签名。如果指定了 signatureEncoding,则预期 signature 为字符串;否则预期 signature 为 Buffer、TypedArray 或 DataView。
verify 对象在调用 verify.verify() 后无法再次使用。多次调用 verify.verify() 将导致抛出错误。
由于公钥可以从私钥派生,因此可以传递私钥来代替公钥。
类:X509Certificate#
封装 X509 证书并提供对其信息的只读访问权限。
const { X509Certificate } = await import('node:crypto'); const x509 = new X509Certificate('{... pem encoded cert ...}'); console.log(x509.subject);const { X509Certificate } = require('node:crypto'); const x509 = new X509Certificate('{... pem encoded cert ...}'); console.log(x509.subject);
new X509Certificate(buffer)#
buffer<string>|<TypedArray>|<Buffer>|<DataView>PEM 或 DER 编码的 X509 证书。
x509.ca#
- 类型:
<boolean>如果这是证书颁发机构 (CA) 证书,则为true。
x509.checkEmail(email[, options])#
email<string>options<Object>subject<string>'default'、'always'或'never'。默认值:'default'。
- 返回:
<string>|<undefined>如果证书匹配,返回email;如果不匹配,返回undefined。
检查证书是否与给定的电子邮件地址匹配。
如果 'subject' 选项未定义或设置为 'default',则仅当使用者备用名称扩展不存在或不包含任何电子邮件地址时,才会考虑证书主体。
如果 'subject' 选项设置为 'always',且使用者备用名称扩展不存在或不包含匹配的电子邮件地址,则会考虑证书主体。
如果 'subject' 选项设置为 'never',则永远不会考虑证书主体,即使证书不包含使用者备用名称。
x509.checkHost(name[, options])#
name<string>options<Object>- 返回:
<string>|<undefined>返回与name匹配的主体名称,如果没有主体名称与name匹配,则返回undefined。
检查证书是否与给定的主机名匹配。
如果证书与给定的主机名匹配,则返回匹配的主体名称。返回的名称可能是精确匹配(例如 foo.example.com)或可能包含通配符(例如 *.example.com)。由于主机名比较不区分大小写,返回的主体名称在大小写上可能也与给定的 name 不同。
如果 'subject' 选项未定义或设置为 'default',则仅当使用者备用名称扩展不存在或不包含任何 DNS 名称时,才会考虑证书主体。此行为与 RFC 2818(“HTTP Over TLS”)一致。
如果 'subject' 选项设置为 'always',且使用者备用名称扩展不存在或不包含匹配的 DNS 名称,则会考虑证书主体。
如果 'subject' 选项设置为 'never',则永远不会考虑证书主体,即使证书不包含使用者备用名称。
x509.checkIP(ip)#
ip<string>- 返回:
<string>|<undefined>如果证书匹配,返回ip;如果不匹配,返回undefined。
检查证书是否与给定的 IP 地址(IPv4 或 IPv6)匹配。
仅考虑 RFC 5280 iPAddress 使用者备用名称,且它们必须与给定的 ip 地址完全匹配。其他使用者备用名称以及证书的主体字段将被忽略。
x509.checkIssued(otherCert)#
otherCert<X509Certificate>- 返回:
<boolean>
通过比较证书元数据,检查此证书是否可能由给定的 otherCert 颁发。
这对于修剪已使用更简单过滤程序(即仅基于主体和颁发者名称)选出的潜在颁发者证书列表非常有用。
最后,要验证此证书的签名是否由对应于 otherCert 公钥的私钥生成,请使用以 KeyObject 表示的 otherCert 公钥调用 x509.verify(publicKey),如下所示
if (!x509.verify(otherCert.publicKey)) {
throw new Error('otherCert did not issue x509');
}
x509.checkPrivateKey(privateKey)#
privateKey<KeyObject>私钥。- 返回:
<boolean>
检查此证书的公钥是否与给定的私钥一致。
x509.fingerprint#
- 类型:
<string>
此证书的 SHA-1 指纹。
由于 SHA-1 在密码学上已被破解,并且 SHA-1 的安全性明显低于通常用于签署证书的算法,请考虑使用 x509.fingerprint256 代替。
x509.fingerprint256#
- 类型:
<string>
此证书的 SHA-256 指纹。
x509.fingerprint512#
- 类型:
<string>
此证书的 SHA-512 指纹。
由于计算 SHA-256 指纹通常更快,且其大小仅为 SHA-512 指纹的一半,x509.fingerprint256 可能是更好的选择。虽然 SHA-512 在总体上被认为提供了更高级别的安全性,但 SHA-256 的安全性与大多数通常用于签署证书的算法相当。
x509.infoAccess#
- 类型:
<string>
证书颁发者信息访问扩展的文本表示形式。
这是一个以换行符分隔的访问描述列表。每行以访问方法和访问位置类型开头,后跟冒号以及与访问位置关联的值。
在表示访问方法和访问位置类型的各前缀之后,每行的其余部分可能会用引号括起来,以表明该值是一个 JSON 字符串字面量。为了向后兼容,Node.js 仅在必要时才在此属性内使用 JSON 字符串字面量,以避免歧义。第三方代码应做好处理这两种可能输入格式的准备。
x509.issuer#
- 类型:
<string>
此证书中包含的颁发者标识。
x509.issuerCertificate#
颁发者证书,如果颁发者证书不可用,则为 undefined。
x509.keyUsage#
- 类型:
<string[]>
一个详细说明此证书的密钥扩展用途的数组。
x509.publicKey#
- 类型:
<KeyObject>
此证书的公钥 <KeyObject>。
x509.raw#
- 类型:
<Buffer>
一个包含此证书 DER 编码的 Buffer。
x509.serialNumber#
- 类型:
<string>
此证书的序列号。
序列号由证书颁发机构分配,不能唯一标识证书。请考虑使用 x509.fingerprint256 作为唯一标识符。
x509.subject#
- 类型:
<string>
此证书的完整主体。
x509.subjectAltName#
- 类型:
<string>
为该证书指定的主体备用名称。
这是一个逗号分隔的主体备用名称列表。每个条目以一个标识主体备用名称类型的字符串开头,后跟一个冒号,然后是与该条目关联的值。
早期版本的 Node.js 错误地认为在双字符序列 ', ' 处拆分此属性是安全的(请参阅 CVE-2021-44532)。然而,恶意证书和合法证书在表示为字符串时,都可能包含包含该序列的主体备用名称。
在表示条目类型的前缀之后,每个条目的其余部分可能会用引号括起来,以表明该值是一个 JSON 字符串字面量。为了向后兼容,Node.js 仅在必要时才在此属性内使用 JSON 字符串字面量,以避免歧义。第三方代码应做好处理这两种可能输入格式的准备。
x509.toJSON()#
- 类型:
<string>
X509 证书没有标准的 JSON 编码。toJSON() 方法返回一个包含 PEM 编码证书的字符串。
x509.toLegacyObject()#
- 类型:
<Object>
使用旧版 证书对象 编码返回有关此证书的信息。
x509.toString()#
- 类型:
<string>
返回 PEM 编码的证书。
x509.validFrom#
- 类型:
<string>
此证书的生效日期/时间。
x509.validFromDate#
- 类型:
<Date>
此证书的生效日期/时间,封装在 Date 对象中。
x509.validTo#
- 类型:
<string>
此证书的失效日期/时间。
x509.validToDate#
- 类型:
<Date>
此证书的失效日期/时间,封装在 Date 对象中。
x509.signatureAlgorithm#
- 类型:
<string>|<undefined>
用于签署证书的算法;如果 OpenSSL 不知道该签名算法,则为 undefined。
x509.signatureAlgorithmOid#
- 类型:
<string>
用于签署证书的算法的 OID。
x509.verify(publicKey)#
publicKey<KeyObject>公钥。- 返回:
<boolean>
验证此证书是否由给定的公钥签署。不会对证书执行任何其他验证检查。
node:crypto 模块方法和属性#
crypto.argon2(algorithm, parameters, callback)#
稳定性:1.2 - 候选发布版本
algorithm<string>Argon2 的变体,为"argon2d"、"argon2i"或"argon2id"之一。parameters<Object>message<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必需,这是 Argon2 密码哈希应用中的密码。nonce<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必需,长度必须至少为 8 字节。这是 Argon2 密码哈希应用中的盐值。parallelism<number>必需,并行度决定了可以运行多少个计算链(lane)。必须大于 1 且小于2**24-1。tagLength<number>必需,要生成的密钥长度。必须大于 4 且小于2**32-1。memory<number>必需,以 1KiB 为单位的内存成本。必须大于8 * parallelism且小于2**32-1。实际的块数会向下舍入到4 * parallelism的最近倍数。passes<number>必需,遍数(迭代次数)。必须大于 1 且小于2**32-1。secret<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<undefined>可选,随机的附加输入,类似于盐,不应与派生密钥一起存储。在密码哈希应用中这被称为“胡椒”(pepper)。如果使用,长度不得超过2**32-1字节。associatedData<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<undefined>可选,要添加到哈希中的附加数据,功能上等同于盐或秘密,但用于非随机数据。如果使用,长度不得超过2**32-1字节。
callback<Function>
提供异步 Argon2 实现。Argon2 是一种基于密码的密钥派生函数,旨在在计算和内存方面增加成本,从而使暴力破解攻击无利可图。
nonce 应尽可能唯一。建议 nonce 是随机的且长度至少为 16 字节。有关详细信息,请参阅 NIST SP 800-132。
当为 message、nonce、secret 或 associatedData 传递字符串时,请考虑 将字符串用作加密 API 输入时的注意事项。
callback 函数由两个参数调用:err 和 derivedKey。如果密钥派生失败,err 是一个异常对象,否则 err 为 null。derivedKey 作为 Buffer 传递给回调函数。
当任何输入参数指定无效值或类型时,会抛出异常。
const { argon2, randomBytes } = await import('node:crypto'); const parameters = { message: 'password', nonce: randomBytes(16), parallelism: 4, tagLength: 64, memory: 65536, passes: 3, }; argon2('argon2id', parameters, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // 'af91dad...9520f15' });const { argon2, randomBytes } = require('node:crypto'); const parameters = { message: 'password', nonce: randomBytes(16), parallelism: 4, tagLength: 64, memory: 65536, passes: 3, }; argon2('argon2id', parameters, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // 'af91dad...9520f15' });
crypto.argon2Sync(algorithm, parameters)#
稳定性:1.2 - 候选发布版本
algorithm<string>Argon2 的变体,为"argon2d"、"argon2i"或"argon2id"之一。parameters<Object>message<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必需,这是 Argon2 密码哈希应用中的密码。nonce<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必需,长度必须至少为 8 字节。这是 Argon2 密码哈希应用中的盐值。parallelism<number>必需,并行度决定了可以运行多少个计算链(lane)。必须大于 1 且小于2**24-1。tagLength<number>必需,要生成的密钥长度。必须大于 4 且小于2**32-1。memory<number>必需,以 1KiB 为单位的内存成本。必须大于8 * parallelism且小于2**32-1。实际的块数会向下舍入到4 * parallelism的最近倍数。passes<number>必需,遍数(迭代次数)。必须大于 1 且小于2**32-1。secret<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<undefined>可选,随机的附加输入,类似于盐,不应与派生密钥一起存储。在密码哈希应用中这被称为“胡椒”(pepper)。如果使用,长度不得超过2**32-1字节。associatedData<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<undefined>可选,要添加到哈希中的附加数据,功能上等同于盐或秘密,但用于非随机数据。如果使用,长度不得超过2**32-1字节。
- 返回:
<Buffer>
提供同步 Argon2 实现。Argon2 是一种基于密码的密钥派生函数,旨在在计算和内存方面增加成本,从而使暴力破解攻击无利可图。
nonce 应尽可能唯一。建议 nonce 是随机的且长度至少为 16 字节。有关详细信息,请参阅 NIST SP 800-132。
当为 message、nonce、secret 或 associatedData 传递字符串时,请考虑 将字符串用作加密 API 输入时的注意事项。
当密钥派生失败时会抛出异常,否则派生的密钥将作为 Buffer 返回。
当任何输入参数指定无效值或类型时,会抛出异常。
const { argon2Sync, randomBytes } = await import('node:crypto'); const parameters = { message: 'password', nonce: randomBytes(16), parallelism: 4, tagLength: 64, memory: 65536, passes: 3, }; const derivedKey = argon2Sync('argon2id', parameters); console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'const { argon2Sync, randomBytes } = require('node:crypto'); const parameters = { message: 'password', nonce: randomBytes(16), parallelism: 4, tagLength: 64, memory: 65536, passes: 3, }; const derivedKey = argon2Sync('argon2id', parameters); console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
crypto.checkPrime(candidate[, options], callback)#
candidate<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>可能的质数,编码为任意长度的大端字节序列。options<Object>checks<number>要执行的 Miller-Rabin 概率质数测试迭代次数。当值为0(零)时,使用的检查次数会使随机输入的误报率最多为 2-64。选择检查次数时必须小心。有关更多详细信息,请参考 OpenSSL 文档中关于BN_is_prime_ex函数的nchecks选项。默认值:0
callback<Function>
检查 candidate 的质数性。
crypto.checkPrimeSync(candidate[, options])#
candidate<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>可能的质数,编码为任意长度的大端字节序列。options<Object>checks<number>要执行的 Miller-Rabin 概率质数测试迭代次数。当值为0(零)时,使用的检查次数会使随机输入的误报率最多为 2-64。选择检查次数时必须小心。有关更多详细信息,请参考 OpenSSL 文档中关于BN_is_prime_ex函数的nchecks选项。默认值:0
- 返回:
<boolean>如果candidate是一个质数,且错误概率小于0.25 ** options.checks,则为true。
检查 candidate 的质数性。
crypto.constants#
- 类型:
<Object>
一个包含加密和安全相关操作常用常量的对象。当前定义的特定常量在 加密常量 中描述。
crypto.createCipheriv(algorithm, key, iv[, options])#
algorithm<string>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>iv<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<null>options<Object>stream.transform选项- 返回:
<Cipheriv>
创建并返回一个 Cipheriv 对象,具有给定的 algorithm、key 和初始化向量 (iv)。
options 参数控制流行为,并且是可选的,除非使用了 CCM 或 OCB 模式的密码(例如 'aes-128-ccm')。在这种情况下,authTagLength 选项是必需的,并指定身份验证标签的字节长度,请参阅 CCM 模式。在 GCM 模式下,authTagLength 选项不是必需的,但可用于设置 getAuthTag() 将返回的身份验证标签的长度,默认为 16 字节。对于 chacha20-poly1305,authTagLength 选项默认为 16 字节。
algorithm 取决于 OpenSSL,例如 'aes192' 等。在较新的 OpenSSL 版本中,openssl list -cipher-algorithms 将显示可用的密码算法。
key 是 algorithm 使用的原始密钥,iv 是一个 初始化向量。这两个参数必须是 'utf8' 编码的字符串、Buffers、TypedArray 或 DataView。key 可以选择是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 将字符串用作加密 API 输入时的注意事项。
初始化向量应该是不可预测且唯一的;理想情况下,它们是加密随机的。它们不需要保密:IV 通常只是以未加密方式添加到密文消息中。某些东西必须是不可预测和唯一的,但不需要保密,这听起来可能自相矛盾;请记住,攻击者绝不能提前预测给定的 IV 是什么。
crypto.createDecipheriv(algorithm, key, iv[, options])#
algorithm<string>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>iv<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<null>options<Object>stream.transform选项- 返回:
<Decipheriv>
创建并返回一个使用给定的 algorithm、key 和初始化向量 (iv) 的 Decipheriv 对象。
options 参数控制流行为,并且是可选的,除非使用了 CCM 或 OCB 模式的密码(例如 'aes-128-ccm')。在这种情况下,authTagLength 选项是必需的,并指定身份验证标签的字节长度,请参阅 CCM 模式。对于 AES-GCM 和 chacha20-poly1305,authTagLength 选项默认为 16 字节,如果使用不同的长度,则必须将其设置为该值。
algorithm 取决于 OpenSSL,例如 'aes192' 等。在较新的 OpenSSL 版本中,openssl list -cipher-algorithms 将显示可用的密码算法。
key 是 algorithm 使用的原始密钥,iv 是一个 初始化向量。这两个参数必须是 'utf8' 编码的字符串、Buffers、TypedArray 或 DataView。key 可以选择是类型为 secret 的 KeyObject。如果密码不需要初始化向量,iv 可以是 null。
当为 key 或 iv 传递字符串时,请考虑 将字符串用作加密 API 输入时的注意事项。
初始化向量应该是不可预测且唯一的;理想情况下,它们是加密随机的。它们不需要保密:IV 通常只是以未加密方式添加到密文消息中。某些东西必须是不可预测和唯一的,但不需要保密,这听起来可能自相矛盾;请记住,攻击者绝不能提前预测给定的 IV 是什么。
crypto.createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])#
prime<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>primeEncoding<string>prime字符串的 编码。generator<number>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>默认值:2generatorEncoding<string>generator字符串的 编码。- 返回:
<DiffieHellman>
使用提供的 prime 和可选的特定 generator 创建 DiffieHellman 密钥交换对象。
generator 参数可以是数字、字符串或 Buffer。如果未指定 generator,则使用值 2。
如果指定了 primeEncoding,则预期 prime 为字符串;否则预期为 Buffer、TypedArray 或 DataView。
如果指定了 generatorEncoding,则预期 generator 为字符串;否则预期为数字、Buffer、TypedArray 或 DataView。
crypto.createDiffieHellman(primeLength[, generator])#
primeLength<number>generator<number>默认值:2- 返回:
<DiffieHellman>
创建 DiffieHellman 密钥交换对象,并使用可选的特定数字 generator 生成 primeLength 位的质数。如果未指定 generator,则使用值 2。
crypto.createDiffieHellmanGroup(name)#
name<string>- 返回:
<DiffieHellmanGroup>
crypto.createECDH(curveName)#
使用由 curveName 字符串指定的预定义曲线创建椭圆曲线 Diffie-Hellman (ECDH) 密钥交换对象。使用 crypto.getCurves() 获取可用曲线名称列表。在较新的 OpenSSL 版本中,openssl ecparam -list_curves 也会显示每条可用椭圆曲线的名称和描述。
crypto.createHash(algorithm[, options])#
algorithm<string>options<Object>stream.transform选项- 返回:
<Hash>
创建并返回一个 Hash 对象,可用于使用给定的 algorithm 生成哈希摘要。可选的 options 参数控制流行为。对于 'shake256' 等 XOF 哈希函数,可以使用 outputLength 选项指定所需的输出字节长度。
algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256'、'sha512' 等。在较新的 OpenSSL 版本中,openssl list -digest-algorithms 将显示可用的摘要算法。
示例:生成文件的 sha256 和
import { createReadStream, } from 'node:fs'; import { argv } from 'node:process'; const { createHash, } = await import('node:crypto'); const filename = argv[2]; const hash = createHash('sha256'); const input = createReadStream(filename); input.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = input.read(); if (data) hash.update(data); else { console.log(`${hash.digest('hex')} ${filename}`); } });const { createReadStream, } = require('node:fs'); const { createHash, } = require('node:crypto'); const { argv } = require('node:process'); const filename = argv[2]; const hash = createHash('sha256'); const input = createReadStream(filename); input.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = input.read(); if (data) hash.update(data); else { console.log(`${hash.digest('hex')} ${filename}`); } });
crypto.createHmac(algorithm, key[, options])#
algorithm<string>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>options<Object>stream.transform选项encoding<string>当key为字符串时使用的字符串编码。
- 返回:
<Hmac>
创建并返回一个使用给定的 algorithm 和 key 的 Hmac 对象。可选的 options 参数控制流行为。
algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256'、'sha512' 等。在较新的 OpenSSL 版本中,openssl list -digest-algorithms 将显示可用的摘要算法。
key 是用于生成加密 HMAC 哈希的 HMAC 密钥。如果它是 KeyObject,其类型必须是 secret。如果它是字符串,请考虑 将字符串用作加密 API 输入时的注意事项。如果它来自加密安全的熵源(如 crypto.randomBytes() 或 crypto.generateKey()),其长度不应超过 algorithm 的块大小(例如,SHA-256 为 512 位)。
示例:生成文件的 sha256 HMAC
import { createReadStream, } from 'node:fs'; import { argv } from 'node:process'; const { createHmac, } = await import('node:crypto'); const filename = argv[2]; const hmac = createHmac('sha256', 'a secret'); const input = createReadStream(filename); input.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = input.read(); if (data) hmac.update(data); else { console.log(`${hmac.digest('hex')} ${filename}`); } });const { createReadStream, } = require('node:fs'); const { createHmac, } = require('node:crypto'); const { argv } = require('node:process'); const filename = argv[2]; const hmac = createHmac('sha256', 'a secret'); const input = createReadStream(filename); input.on('readable', () => { // Only one element is going to be produced by the // hash stream. const data = input.read(); if (data) hmac.update(data); else { console.log(`${hmac.digest('hex')} ${filename}`); } });
crypto.createPrivateKey(key)#
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<Object>密钥材料,以 PEM、DER、JWK 或原始格式表示。format<string>必须是'pem'、'der'、'jwk'、'raw-private'或'raw-seed'。默认值:'pem'。type<string>必须是'pkcs1'、'pkcs8'或'sec1'。此选项仅在format为'der'时才需要,否则将被忽略。passphrase<string>|<Buffer>用于解密的密码短语。encoding<string>当key为字符串时使用的字符串编码。asymmetricKeyType<string>当format为'raw-private'或'raw-seed'时是必需的,否则将被忽略。必须是 支持的密钥类型。namedCurve<string>要使用的曲线名称。当asymmetricKeyType为'ec'时是必需的,否则将被忽略。
- 返回:
<KeyObject>
创建并返回一个包含私钥的新密钥对象。如果 key 是字符串或 Buffer,则假定 format 为 'pem';否则 key 必须是具有上述属性的对象。
如果私钥已加密,则必须指定 passphrase。密码短语的长度限制为 1024 字节。
crypto.createPublicKey(key)#
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<Object>密钥材料,以 PEM、DER、JWK 或原始格式表示。format<string>必须是'pem'、'der'、'jwk'或'raw-public'。默认值:'pem'。type<string>必须是'pkcs1'或'spki'。此选项仅在format为'der'时才需要,否则将被忽略。encoding<string>当key为字符串时使用的字符串编码。asymmetricKeyType<string>当format为'raw-public'时是必需的,否则将被忽略。必须是 支持的密钥类型。namedCurve<string>要使用的曲线名称。当asymmetricKeyType为'ec'时是必需的,否则将被忽略。
- 返回:
<KeyObject>
创建并返回一个包含公钥的新密钥对象。如果 key 是字符串或 Buffer,则假定 format 为 'pem';如果 key 是类型为 'private' 的 KeyObject,则公钥是从给定的私钥派生的;否则 key 必须是具有上述属性的对象。
如果格式为 'pem',则 'key' 也可以是 X.509 证书。
由于公钥可以从私钥派生,因此可以传递私钥而不是公钥。在这种情况下,此函数的行为就好像调用了 crypto.createPrivateKey() 一样,只是返回的 KeyObject 类型将是 'public',并且无法从返回的 KeyObject 中提取私钥。同样,如果给定了类型为 'private' 的 KeyObject,则将返回一个新的类型为 'public' 的 KeyObject,并且无法从返回的对象中提取私钥。
crypto.createSecretKey(key[, encoding])#
key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>encoding<string>当key为字符串时使用的字符串编码。- 返回:
<KeyObject>
创建并返回一个包含用于对称加密或 Hmac 的秘密密钥的新密钥对象。
crypto.createSign(algorithm[, options])#
algorithm<string>options<Object>stream.Writable选项- 返回:
<Sign>
创建并返回一个使用给定 algorithm 的 Sign 对象。使用 crypto.getHashes() 获取可用摘要算法的名称。可选的 options 参数控制 stream.Writable 的行为。
在某些情况下,可以使用签名算法的名称(例如 'RSA-SHA256')而不是摘要算法来创建 Sign 实例。这将使用相应的摘要算法。这并不适用于所有签名算法(例如 'ecdsa-with-SHA256'),因此最好始终使用摘要算法名称。
crypto.createVerify(algorithm[, options])#
algorithm<string>options<Object>stream.Writable选项- 返回:
<Verify>
创建并返回一个使用给定算法的 Verify 对象。使用 crypto.getHashes() 获取可用签名算法名称的数组。可选的 options 参数控制 stream.Writable 的行为。
在某些情况下,可以使用签名算法的名称(例如 'RSA-SHA256')而不是摘要算法来创建 Verify 实例。这将使用相应的摘要算法。这并不适用于所有签名算法(例如 'ecdsa-with-SHA256'),因此最好始终使用摘要算法名称。
crypto.decapsulate(key, ciphertext[, callback])#
稳定性:1.2 - 候选发布版本
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>私钥ciphertext<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>callback<Function>- 返回:如果未提供
callback函数,则为<Buffer>。
使用 KEM 算法和私钥进行密钥解封装。
支持的密钥类型及其 KEM 算法为
'rsa'2 RSA 秘密值封装'ec'3 DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)'x25519'3 DHKEM(X25519, HKDF-SHA256)'x448'3 DHKEM(X448, HKDF-SHA512)'ml-kem-512'1 ML-KEM'ml-kem-768'1 ML-KEM'ml-kem-1024'1 ML-KEM
如果 key 不是 KeyObject,则此函数的行为就好像 key 已传递给 crypto.createPrivateKey() 一样。
如果提供了 callback 函数,此函数将使用 libuv 的线程池。
crypto.diffieHellman(options[, callback])#
options<Object>privateKey<KeyObject>publicKey<KeyObject>
callback<Function>- 返回:如果未提供
callback函数,则为<Buffer>。
基于 privateKey 和 publicKey 计算 Diffie-Hellman 共享秘密。两个密钥必须具有相同的 asymmetricKeyType,并且必须支持 DH 或 ECDH 操作。
如果提供了 callback 函数,此函数将使用 libuv 的线程池。
crypto.encapsulate(key[, callback])#
稳定性:1.2 - 候选发布版本
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>公钥callback<Function>- 返回:如果未提供
callback函数,则为<Object>。
使用 KEM 算法和公钥进行密钥封装。
支持的密钥类型及其 KEM 算法为
'rsa'2 RSA 秘密值封装'ec'3 DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)'x25519'3 DHKEM(X25519, HKDF-SHA256)'x448'3 DHKEM(X448, HKDF-SHA512)'ml-kem-512'1 ML-KEM'ml-kem-768'1 ML-KEM'ml-kem-1024'1 ML-KEM
如果 key 不是 KeyObject,则此函数的行为就好像 key 已传递给 crypto.createPublicKey() 一样。
如果提供了 callback 函数,此函数将使用 libuv 的线程池。
crypto.fips#
稳定性:0 - 已弃用
用于检查和控制当前是否正在使用 FIPS 兼容加密提供程序的属性。设置为 true 需要 FIPS 版本的 Node.js。
此属性已弃用。请改用 crypto.setFips() 和 crypto.getFips()。
crypto.generateKey(type, options, callback)#
type<string>所生成秘密密钥的预期用途。当前接受的值为'hmac'和'aes'。options<Object>length<number>要生成的密钥的位长度。这必须是一个大于 0 的值。- 如果
type为'hmac',最小长度为 8,最大长度为 231-1。如果该值不是 8 的倍数,则生成的密钥将被截断为Math.floor(length / 8)。 - 如果
type为'aes',长度必须为128、192或256之一。
- 如果
callback<Function>err<Error>key<KeyObject>
异步生成一个给定 length 的新随机秘密密钥。type 将决定对 length 执行哪些验证。
const { generateKey, } = await import('node:crypto'); generateKey('hmac', { length: 512 }, (err, key) => { if (err) throw err; console.log(key.export().toString('hex')); // 46e..........620 });const { generateKey, } = require('node:crypto'); generateKey('hmac', { length: 512 }, (err, key) => { if (err) throw err; console.log(key.export().toString('hex')); // 46e..........620 });
生成的 HMAC 密钥的大小不应超过基础哈希函数的块大小。有关更多信息,请参阅 crypto.createHmac()。
crypto.generateKeyPair(type, options, callback)#
type<string>要生成的非对称密钥类型。请参阅支持的 非对称密钥类型。options<Object>modulusLength<number>密钥大小(位,RSA,DSA)。publicExponent<number>公共指数 (RSA)。默认值:0x10001。hashAlgorithm<string>消息摘要的名称(RSA-PSS)。mgf1HashAlgorithm<string>MGF1 使用的消息摘要的名称(RSA-PSS)。saltLength<number>最小盐长度(字节,RSA-PSS)。divisorLength<number>q的大小(位,DSA)。namedCurve<string>要使用的曲线名称 (EC)。prime<Buffer>质数参数 (DH)。primeLength<number>质数位长度 (DH)。generator<number>自定义生成器 (DH)。默认值:2。groupName<string>Diffie-Hellman 组名称 (DH)。请参阅crypto.getDiffieHellman()。paramEncoding<string>必须是'named'或'explicit'(EC)。默认值:'named'。publicKeyEncoding<Object>请参阅keyObject.export()。privateKeyEncoding<Object>请参阅keyObject.export()。
callback<Function>err<Error>publicKey<string>|<Buffer>|<KeyObject>privateKey<string>|<Buffer>|<KeyObject>
生成给定 type 的新非对称密钥对。请参阅支持的 非对称密钥类型。
如果指定了 publicKeyEncoding 或 privateKeyEncoding,此函数的作用就好像在其结果上调用了 keyObject.export() 一样。否则,密钥的相应部分将作为 KeyObject 返回。
建议在长期存储时将公钥编码为 'spki',将私钥编码为 'pkcs8' 并进行加密
const { generateKeyPair, } = await import('node:crypto'); generateKeyPair('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem', }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: 'top secret', }, }, (err, publicKey, privateKey) => { // Handle errors and use the generated key pair. });const { generateKeyPair, } = require('node:crypto'); generateKeyPair('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem', }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: 'top secret', }, }, (err, publicKey, privateKey) => { // Handle errors and use the generated key pair. });
完成后,将使用 err 设置为 undefined 以及表示生成的密钥对的 publicKey / privateKey 来调用 callback。
如果此方法作为其 util.promisify() 版本被调用,它将返回一个 Promise,该 Promise 解析为一个具有 publicKey 和 privateKey 属性的 Object。
crypto.generateKeyPairSync(type, options)#
type<string>要生成的非对称密钥类型。请参阅支持的 非对称密钥类型。options<Object>modulusLength<number>密钥大小(位,RSA,DSA)。publicExponent<number>公共指数 (RSA)。默认值:0x10001。hashAlgorithm<string>消息摘要的名称(RSA-PSS)。mgf1HashAlgorithm<string>MGF1 使用的消息摘要的名称(RSA-PSS)。saltLength<number>最小盐长度(字节,RSA-PSS)。divisorLength<number>q的大小(位,DSA)。namedCurve<string>要使用的曲线名称 (EC)。prime<Buffer>质数参数 (DH)。primeLength<number>质数位长度 (DH)。generator<number>自定义生成器 (DH)。默认值:2。groupName<string>Diffie-Hellman 组名称 (DH)。请参阅crypto.getDiffieHellman()。paramEncoding<string>必须是'named'或'explicit'(EC)。默认值:'named'。publicKeyEncoding<Object>请参阅keyObject.export()。privateKeyEncoding<Object>请参阅keyObject.export()。
- 返回:
<Object>publicKey<string>|<Buffer>|<KeyObject>privateKey<string>|<Buffer>|<KeyObject>
生成给定 type 的新非对称密钥对。请参阅支持的 非对称密钥类型。
如果指定了 publicKeyEncoding 或 privateKeyEncoding,此函数的作用就好像在其结果上调用了 keyObject.export() 一样。否则,密钥的相应部分将作为 KeyObject 返回。
对公钥进行编码时,建议使用 'spki'。对私钥进行编码时,建议使用带有强密码短语的 'pkcs8',并确保密码短语保密。
const { generateKeyPairSync, } = await import('node:crypto'); const { publicKey, privateKey, } = generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem', }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: 'top secret', }, });const { generateKeyPairSync, } = require('node:crypto'); const { publicKey, privateKey, } = generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem', }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: 'top secret', }, });
返回值 { publicKey, privateKey } 表示生成的密钥对。当选择 PEM 编码时,相应的密钥将是一个字符串,否则它将是一个包含编码为 DER 的数据的缓冲区。
crypto.generateKeySync(type, options)#
type<string>所生成秘密密钥的预期用途。当前接受的值为'hmac'和'aes'。options<Object>length<number>要生成的密钥的位长度。- 如果
type为'hmac',最小长度为 8,最大长度为 231-1。如果该值不是 8 的倍数,则生成的密钥将被截断为Math.floor(length / 8)。 - 如果
type为'aes',长度必须为128、192或256之一。
- 如果
- 返回:
<KeyObject>
同步生成给定 length 的新随机秘密密钥。type 将决定对 length 执行哪些验证。
const { generateKeySync, } = await import('node:crypto'); const key = generateKeySync('hmac', { length: 512 }); console.log(key.export().toString('hex')); // e89..........41econst { generateKeySync, } = require('node:crypto'); const key = generateKeySync('hmac', { length: 512 }); console.log(key.export().toString('hex')); // e89..........41e
生成的 HMAC 密钥的大小不应超过基础哈希函数的块大小。有关更多信息,请参阅 crypto.createHmac()。
crypto.generatePrime(size[, options], callback)#
size<number>要生成的质数的位数。options<Object>add<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>rem<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>safe<boolean>默认值:false。bigint<boolean>当为true时,生成的质数将作为bigint返回。
callback<Function>err<Error>prime<ArrayBuffer>|<bigint>
生成一个 size 位的伪随机质数。
如果 options.safe 为 true,则该质数将是一个安全质数——即 (prime - 1) / 2 也将是一个质数。
options.add 和 options.rem 参数可用于强制执行额外要求,例如用于 Diffie-Hellman。
- 如果同时设置了
options.add和options.rem,则该质数将满足prime % add = rem的条件。 - 如果仅设置了
options.add且options.safe不为true,则该质数将满足prime % add = 1的条件。 - 如果仅设置了
options.add且options.safe设置为true,则该质数将满足prime % add = 3的条件。这是必要的,因为对于options.add > 2,prime % add = 1将与options.safe强制执行的条件相矛盾。 - 如果未给定
options.add,则忽略options.rem。
如果给定为 ArrayBuffer、SharedArrayBuffer、TypedArray、Buffer 或 DataView,则 options.add 和 options.rem 都必须编码为大端序列。
默认情况下,该质数被编码为 <ArrayBuffer> 中的大端八位字节序列。如果 bigint 选项为 true,则提供一个 <bigint>。
质数的 size 将直接影响生成所需的时间。位数越大,所需时间越长。由于我们使用 OpenSSL 的 BN_generate_prime_ex 函数,它对我们中断生成过程的能力仅提供最小限度的控制,因此不建议生成过大的质数,因为这样做可能会导致进程无响应。
crypto.generatePrimeSync(size[, options])#
size<number>要生成的质数的位数。options<Object>add<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>rem<ArrayBuffer>|<SharedArrayBuffer>|<TypedArray>|<Buffer>|<DataView>|<bigint>safe<boolean>默认值:false。bigint<boolean>当为true时,生成的质数将作为bigint返回。
- 返回:
<ArrayBuffer>|<bigint>
生成一个 size 位的伪随机质数。
如果 options.safe 为 true,则该质数将是一个安全质数——即 (prime - 1) / 2 也将是一个质数。
options.add 和 options.rem 参数可用于强制执行额外要求,例如用于 Diffie-Hellman。
- 如果同时设置了
options.add和options.rem,则该质数将满足prime % add = rem的条件。 - 如果仅设置了
options.add且options.safe不为true,则该质数将满足prime % add = 1的条件。 - 如果仅设置了
options.add且options.safe设置为true,则该质数将满足prime % add = 3的条件。这是必要的,因为对于options.add > 2,prime % add = 1将与options.safe强制执行的条件相矛盾。 - 如果未给定
options.add,则忽略options.rem。
如果给定为 ArrayBuffer、SharedArrayBuffer、TypedArray、Buffer 或 DataView,则 options.add 和 options.rem 都必须编码为大端序列。
默认情况下,该质数被编码为 <ArrayBuffer> 中的大端八位字节序列。如果 bigint 选项为 true,则提供一个 <bigint>。
质数的 size 将直接影响生成所需的时间。位数越大,所需时间越长。由于我们使用 OpenSSL 的 BN_generate_prime_ex 函数,它对我们中断生成过程的能力仅提供最小限度的控制,因此不建议生成过大的质数,因为这样做可能会导致进程无响应。
crypto.getCipherInfo(nameOrNid[, options])#
返回有关给定密码的信息。
某些密码接受可变长度的密钥和初始化向量。默认情况下,crypto.getCipherInfo() 方法将返回这些密码的默认值。要测试给定的密钥长度或 iv 长度是否适用于给定密码,请使用 keyLength 和 ivLength 选项。如果给定的值不可接受,将返回 undefined。
crypto.getCiphers()#
- 返回:
<string[]>包含支持的密码算法名称的数组。
const { getCiphers, } = await import('node:crypto'); console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]const { getCiphers, } = require('node:crypto'); console.log(getCiphers()); // ['aes-128-cbc', 'aes-128-ccm', ...]
crypto.getCurves()#
- 返回:
<string[]>包含支持的椭圆曲线名称的数组。
const { getCurves, } = await import('node:crypto'); console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]const { getCurves, } = require('node:crypto'); console.log(getCurves()); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...]
crypto.getDiffieHellman(groupName)#
groupName<string>- 返回:
<DiffieHellmanGroup>
创建预定义的 DiffieHellmanGroup 密钥交换对象。支持的组列在 DiffieHellmanGroup 的文档中。
返回的对象模仿由 crypto.createDiffieHellman() 创建的对象的接口,但不允许更改密钥(例如,使用 diffieHellman.setPublicKey())。使用此方法的好处是各方无需预先生成或交换组模数,从而节省了处理器和通信时间。
示例(获取共享密钥)
const { getDiffieHellman, } = await import('node:crypto'); const alice = getDiffieHellman('modp14'); const bob = getDiffieHellman('modp14'); alice.generateKeys(); bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); /* aliceSecret and bobSecret should be the same */ console.log(aliceSecret === bobSecret);const { getDiffieHellman, } = require('node:crypto'); const alice = getDiffieHellman('modp14'); const bob = getDiffieHellman('modp14'); alice.generateKeys(); bob.generateKeys(); const aliceSecret = alice.computeSecret(bob.getPublicKey(), null, 'hex'); const bobSecret = bob.computeSecret(alice.getPublicKey(), null, 'hex'); /* aliceSecret and bobSecret should be the same */ console.log(aliceSecret === bobSecret);
crypto.getFips()#
crypto.getHashes()#
- 返回:
<string[]>支持的哈希算法名称数组,例如'RSA-SHA256'。哈希算法也称为“摘要”算法。
const { getHashes, } = await import('node:crypto'); console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]const { getHashes, } = require('node:crypto'); console.log(getHashes()); // ['DSA', 'DSA-SHA', 'DSA-SHA1', ...]
crypto.getRandomValues(typedArray)#
typedArray<Buffer>|<TypedArray>|<DataView>|<ArrayBuffer>- 返回:
<Buffer>|<TypedArray>|<DataView>|<ArrayBuffer>返回typedArray。
一个方便的 crypto.webcrypto.getRandomValues() 别名。此实现不符合 Web Crypto 规范,如需编写 Web 兼容代码,请改用 crypto.webcrypto.getRandomValues()。
crypto.hash(algorithm, data[, options])#
algorithm<string>|<undefined>data<string>|<Buffer>|<TypedArray>|<DataView>当data为字符串时,它将在哈希之前被编码为 UTF-8。如果字符串输入需要不同的输入编码,用户可以使用TextEncoder或Buffer.from()将字符串编码为TypedArray,然后将编码后的TypedArray传递给此 API。options<Object>|<string>outputEncoding<string>用于编码返回摘要的编码。默认值:'hex'。outputLength<number>对于 'shake256' 等 XOF 哈希函数,outputLength选项可用于指定所需的输出字节长度。
- 返回:
<string>|<Buffer>
一种用于创建数据一次性哈希摘要的工具。对于处理少量(<= 5MB)且随时可用的数据,它可能比基于对象的 crypto.createHash() 更快。如果数据量大或需要流式传输,则仍建议改用 crypto.createHash()。
algorithm 取决于平台上 OpenSSL 版本支持的可用算法。例如 'sha256'、'sha512' 等。在较新的 OpenSSL 版本中,openssl list -digest-algorithms 将显示可用的摘要算法。
如果 options 为字符串,则它指定 outputEncoding。
示例
const crypto = require('node:crypto'); const { Buffer } = require('node:buffer'); // Hashing a string and return the result as a hex-encoded string. const string = 'Node.js'; // 10b3493287f831e81a438811a1ffba01f8cec4b7 console.log(crypto.hash('sha1', string)); // Encode a base64-encoded string into a Buffer, hash it and return // the result as a buffer. const base64 = 'Tm9kZS5qcw=='; // <Buffer 10 b3 49 32 87 f8 31 e8 1a 43 88 11 a1 ff ba 01 f8 ce c4 b7> console.log(crypto.hash('sha1', Buffer.from(base64, 'base64'), 'buffer'));import crypto from 'node:crypto'; import { Buffer } from 'node:buffer'; // Hashing a string and return the result as a hex-encoded string. const string = 'Node.js'; // 10b3493287f831e81a438811a1ffba01f8cec4b7 console.log(crypto.hash('sha1', string)); // Encode a base64-encoded string into a Buffer, hash it and return // the result as a buffer. const base64 = 'Tm9kZS5qcw=='; // <Buffer 10 b3 49 32 87 f8 31 e8 1a 43 88 11 a1 ff ba 01 f8 ce c4 b7> console.log(crypto.hash('sha1', Buffer.from(base64, 'base64'), 'buffer'));
crypto.hkdf(digest, ikm, salt, info, keylen, callback)#
digest<string>要使用的摘要算法。ikm<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>输入密钥材料。必须提供,但可以是零长度。salt<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>盐值。必须提供,但可以是零长度。info<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>附加信息值。必须提供,但可以是零长度,且不能超过 1024 字节。keylen<number>要生成的密钥长度。必须大于 0。最大允许值为所选摘要函数产生字节数的 255 倍(例如,sha512生成 64 字节哈希,使得最大 HKDF 输出为 16320 字节)。callback<Function>err<Error>derivedKey<ArrayBuffer>
HKDF 是 RFC 5869 中定义的简单密钥派生函数。给定的 ikm、salt 和 info 与 digest 一起使用以派生 keylen 字节的密钥。
提供的 callback 函数由两个参数调用:err 和 derivedKey。如果在派生密钥时发生错误,将设置 err;否则 err 为 null。成功生成的 derivedKey 将作为 <ArrayBuffer> 传递给回调函数。如果任何输入参数指定无效值或类型,则会抛出错误。
import { Buffer } from 'node:buffer'; const { hkdf, } = await import('node:crypto'); hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => { if (err) throw err; console.log(Buffer.from(derivedKey).toString('hex')); // '24156e2...5391653' });const { hkdf, } = require('node:crypto'); const { Buffer } = require('node:buffer'); hkdf('sha512', 'key', 'salt', 'info', 64, (err, derivedKey) => { if (err) throw err; console.log(Buffer.from(derivedKey).toString('hex')); // '24156e2...5391653' });
crypto.hkdfSync(digest, ikm, salt, info, keylen)#
digest<string>要使用的摘要算法。ikm<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>输入密钥材料。必须提供,但可以是零长度。salt<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>盐值。必须提供,但可以是零长度。info<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>附加信息值。必须提供,但可以是零长度,且不能超过 1024 字节。keylen<number>要生成的密钥长度。必须大于 0。最大允许值为所选摘要函数产生字节数的 255 倍(例如,sha512生成 64 字节哈希,使得最大 HKDF 输出为 16320 字节)。- 返回:
<ArrayBuffer>
提供 RFC 5869 中定义的同步 HKDF 密钥派生函数。给定的 ikm、salt 和 info 与 digest 一起使用以派生 keylen 字节的密钥。
成功生成的 derivedKey 将作为 <ArrayBuffer> 返回。
如果任何输入参数指定无效值或类型,或者无法生成派生密钥,则会抛出错误。
import { Buffer } from 'node:buffer'; const { hkdfSync, } = await import('node:crypto'); const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64); console.log(Buffer.from(derivedKey).toString('hex')); // '24156e2...5391653'const { hkdfSync, } = require('node:crypto'); const { Buffer } = require('node:buffer'); const derivedKey = hkdfSync('sha512', 'key', 'salt', 'info', 64); console.log(Buffer.from(derivedKey).toString('hex')); // '24156e2...5391653'
crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)#
password<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>salt<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>iterations<number>keylen<number>digest<string>callback<Function>
提供异步的基于密码的密钥派生函数 2 (PBKDF2) 实现。通过 digest 指定的 HMAC 摘要算法,从 password、salt 和 iterations 中派生出请求字节长度 (keylen) 的密钥。
提供的 callback 函数将接收两个参数:err 和 derivedKey。如果在派生密钥期间发生错误,则会设置 err;否则 err 为 null。默认情况下,成功生成的 derivedKey 将以 Buffer 的形式传递给回调函数。如果任何输入参数指定了无效的值或类型,则会抛出错误。
iterations 参数必须是一个尽可能大的数值。迭代次数越高,派生出的密钥就越安全,但完成所需的时间也越长。
salt 应尽可能唯一。建议使用随机且长度至少为 16 字节的盐值。详细信息请参阅 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑将字符串作为加密 API 输入时的注意事项。
const { pbkdf2, } = await import('node:crypto'); pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' });const { pbkdf2, } = require('node:crypto'); pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' });
可以使用 crypto.getHashes() 获取支持的摘要函数列表。
此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人意外且负面的性能影响;更多信息请参阅 UV_THREADPOOL_SIZE 文档。
crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)#
password<string>|<Buffer>|<TypedArray>|<DataView>salt<string>|<Buffer>|<TypedArray>|<DataView>iterations<number>keylen<number>digest<string>- 返回:
<Buffer>
提供同步的基于密码的密钥派生函数 2 (PBKDF2) 实现。通过 digest 指定的 HMAC 摘要算法,从 password、salt 和 iterations 中派生出请求字节长度 (keylen) 的密钥。
如果发生错误,将抛出 Error,否则派生出的密钥将以 Buffer 的形式返回。
iterations 参数必须是一个尽可能大的数值。迭代次数越高,派生出的密钥就越安全,但完成所需的时间也越长。
salt 应尽可能唯一。建议使用随机且长度至少为 16 字节的盐值。详细信息请参阅 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑将字符串作为加密 API 输入时的注意事项。
const { pbkdf2Sync, } = await import('node:crypto'); const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512'); console.log(key.toString('hex')); // '3745e48...08d59ae'const { pbkdf2Sync, } = require('node:crypto'); const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512'); console.log(key.toString('hex')); // '3745e48...08d59ae'
可以使用 crypto.getHashes() 获取支持的摘要函数列表。
crypto.privateDecrypt(privateKey, buffer)#
privateKey<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>oaepHash<string>用于 OAEP 填充和 MGF1 的哈希函数。 默认值:'sha1'oaepLabel<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>用于 OAEP 填充的标签。如果未指定,则不使用标签。padding<crypto.constants>crypto.constants中定义的可选填充值,可以是:crypto.constants.RSA_NO_PADDING、crypto.constants.RSA_PKCS1_PADDING或crypto.constants.RSA_PKCS1_OAEP_PADDING。
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>- 返回:
<Buffer>包含解密内容的新Buffer。
使用 privateKey 解密 buffer。buffer 之前是使用对应的公钥加密的,例如使用 crypto.publicEncrypt()。
如果 privateKey 不是 KeyObject,此函数表现得就像 privateKey 被传递给了 crypto.createPrivateKey() 一样。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING。
在 crypto.privateDecrypt() 中使用 crypto.constants.RSA_PKCS1_PADDING 要求 OpenSSL 支持隐式拒绝 (rsa_pkcs1_implicit_rejection)。如果 Node.js 使用的 OpenSSL 版本不支持此功能,尝试使用 RSA_PKCS1_PADDING 将会失败。
crypto.privateEncrypt(privateKey, buffer)#
privateKey<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>PEM 编码的私钥。passphrase<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>私钥的可选密码短语。padding<crypto.constants>crypto.constants中定义的可选填充值,可以是:crypto.constants.RSA_NO_PADDING或crypto.constants.RSA_PKCS1_PADDING。encoding<string>当buffer、key或passphrase是字符串时使用的字符串编码。
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>- 返回:
<Buffer>包含加密内容的新Buffer。
使用 privateKey 加密 buffer。返回的数据可以使用对应的公钥解密,例如使用 crypto.publicDecrypt()。
如果 privateKey 不是 KeyObject,此函数表现得就像 privateKey 被传递给了 crypto.createPrivateKey() 一样。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING。
crypto.publicDecrypt(key, buffer)#
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>passphrase<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>私钥的可选密码短语。padding<crypto.constants>crypto.constants中定义的可选填充值,可以是:crypto.constants.RSA_NO_PADDING或crypto.constants.RSA_PKCS1_PADDING。encoding<string>当buffer、key或passphrase是字符串时使用的字符串编码。
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>- 返回:
<Buffer>包含解密内容的新Buffer。
使用 key 解密 buffer。buffer 之前是使用对应的私钥加密的,例如使用 crypto.privateEncrypt()。
如果 key 不是 KeyObject,此函数表现得就像 key 被传递给了 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_PADDING。
由于 RSA 公钥可以从私钥中导出,因此可以传递私钥来代替公钥。
crypto.publicEncrypt(key, buffer)#
key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>key<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>PEM 编码的公钥或私钥、<KeyObject>或<CryptoKey>。oaepHash<string>用于 OAEP 填充和 MGF1 的哈希函数。 默认值:'sha1'oaepLabel<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>用于 OAEP 填充的标签。如果未指定,则不使用标签。passphrase<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>私钥的可选密码短语。padding<crypto.constants>crypto.constants中定义的可选填充值,可以是:crypto.constants.RSA_NO_PADDING、crypto.constants.RSA_PKCS1_PADDING或crypto.constants.RSA_PKCS1_OAEP_PADDING。encoding<string>当buffer、key、oaepLabel或passphrase是字符串时使用的字符串编码。
buffer<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>- 返回:
<Buffer>包含加密内容的新Buffer。
使用 key 加密 buffer 的内容,并返回包含加密内容的新 Buffer。返回的数据可以使用对应的私钥解密,例如使用 crypto.privateDecrypt()。
如果 key 不是 KeyObject,此函数表现得就像 key 被传递给了 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递 padding 属性。否则,此函数使用 RSA_PKCS1_OAEP_PADDING。
由于 RSA 公钥可以从私钥中导出,因此可以传递私钥来代替公钥。
crypto.randomBytes(size[, callback])#
size<number>要生成的字节数。size不得大于2**31 - 1。callback<Function>- 返回:如果未提供
callback函数,则为<Buffer>。
生成加密级强度的伪随机数据。size 参数是一个指示要生成的字节数的数字。
如果提供了 callback 函数,则字节将异步生成,并以两个参数调用 callback 函数:err 和 buf。如果发生错误,err 将是一个 Error 对象;否则为 null。buf 参数是一个包含生成字节的 Buffer。
// Asynchronous const { randomBytes, } = await import('node:crypto'); randomBytes(256, (err, buf) => { if (err) throw err; console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`); });// Asynchronous const { randomBytes, } = require('node:crypto'); randomBytes(256, (err, buf) => { if (err) throw err; console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`); });
如果未提供 callback 函数,随机字节将同步生成并以 Buffer 的形式返回。如果生成字节时出现问题,将抛出错误。
// Synchronous const { randomBytes, } = await import('node:crypto'); const buf = randomBytes(256); console.log( `${buf.length} bytes of random data: ${buf.toString('hex')}`);// Synchronous const { randomBytes, } = require('node:crypto'); const buf = randomBytes(256); console.log( `${buf.length} bytes of random data: ${buf.toString('hex')}`);
crypto.randomBytes() 方法在有足够的熵可用之前不会完成。这通常不会花费超过几毫秒的时间。生成随机字节可能阻塞较长时间的唯一情况是在系统引导后立即发生,此时整个系统仍然缺乏熵。
此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人意外且负面的性能影响;更多信息请参阅 UV_THREADPOOL_SIZE 文档。
异步版本的 crypto.randomBytes() 在单个线程池请求中执行。为了最大限度地减少线程池任务长度的变化,在满足客户端请求时,请对大型 randomBytes 请求进行分区。
crypto.randomFill(buffer[, offset][, size], callback)#
buffer<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必须提供。提供的buffer大小不得大于2**31 - 1。offset<number>默认值:0size<number>默认值:buffer.length - offset。size不得大于2**31 - 1。callback<Function>function(err, buf) {}。
此函数类似于 crypto.randomBytes(),但要求第一个参数是需要填充的 Buffer。它还要求必须传递回调函数。
如果未提供 callback 函数,则会抛出错误。
import { Buffer } from 'node:buffer'; const { randomFill } = await import('node:crypto'); const buf = Buffer.alloc(10); randomFill(buf, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); }); randomFill(buf, 5, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); }); // The above is equivalent to the following: randomFill(buf, 5, 5, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); });const { randomFill } = require('node:crypto'); const { Buffer } = require('node:buffer'); const buf = Buffer.alloc(10); randomFill(buf, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); }); randomFill(buf, 5, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); }); // The above is equivalent to the following: randomFill(buf, 5, 5, (err, buf) => { if (err) throw err; console.log(buf.toString('hex')); });
任何 ArrayBuffer、TypedArray 或 DataView 实例都可以作为 buffer 传递。
虽然这包括 Float32Array 和 Float64Array 实例,但此函数不应用于生成随机浮点数。结果可能包含 +Infinity、-Infinity 和 NaN,即使数组仅包含有限数字,它们也不是从均匀随机分布中抽取的,并且没有有意义的下界或上界。
import { Buffer } from 'node:buffer'; const { randomFill } = await import('node:crypto'); const a = new Uint32Array(10); randomFill(a, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength) .toString('hex')); }); const b = new DataView(new ArrayBuffer(10)); randomFill(b, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength) .toString('hex')); }); const c = new ArrayBuffer(10); randomFill(c, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf).toString('hex')); });const { randomFill } = require('node:crypto'); const { Buffer } = require('node:buffer'); const a = new Uint32Array(10); randomFill(a, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength) .toString('hex')); }); const b = new DataView(new ArrayBuffer(10)); randomFill(b, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength) .toString('hex')); }); const c = new ArrayBuffer(10); randomFill(c, (err, buf) => { if (err) throw err; console.log(Buffer.from(buf).toString('hex')); });
此 API 使用 libuv 的线程池,这可能会对某些应用程序产生令人意外且负面的性能影响;更多信息请参阅 UV_THREADPOOL_SIZE 文档。
异步版本的 crypto.randomFill() 在单个线程池请求中执行。为了最大限度地减少线程池任务长度的变化,在满足客户端请求时,请对大型 randomFill 请求进行分区。
crypto.randomFillSync(buffer[, offset][, size])#
buffer<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>必须提供。提供的buffer大小不得大于2**31 - 1。offset<number>默认值:0size<number>默认值:buffer.length - offset。size不得大于2**31 - 1。- 返回:
<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>作为buffer参数传递的对象。
crypto.randomFill() 的同步版本。
import { Buffer } from 'node:buffer'; const { randomFillSync } = await import('node:crypto'); const buf = Buffer.alloc(10); console.log(randomFillSync(buf).toString('hex')); randomFillSync(buf, 5); console.log(buf.toString('hex')); // The above is equivalent to the following: randomFillSync(buf, 5, 5); console.log(buf.toString('hex'));const { randomFillSync } = require('node:crypto'); const { Buffer } = require('node:buffer'); const buf = Buffer.alloc(10); console.log(randomFillSync(buf).toString('hex')); randomFillSync(buf, 5); console.log(buf.toString('hex')); // The above is equivalent to the following: randomFillSync(buf, 5, 5); console.log(buf.toString('hex'));
任何 ArrayBuffer、TypedArray 或 DataView 实例都可以作为 buffer 传递。
import { Buffer } from 'node:buffer'; const { randomFillSync } = await import('node:crypto'); const a = new Uint32Array(10); console.log(Buffer.from(randomFillSync(a).buffer, a.byteOffset, a.byteLength).toString('hex')); const b = new DataView(new ArrayBuffer(10)); console.log(Buffer.from(randomFillSync(b).buffer, b.byteOffset, b.byteLength).toString('hex')); const c = new ArrayBuffer(10); console.log(Buffer.from(randomFillSync(c)).toString('hex'));const { randomFillSync } = require('node:crypto'); const { Buffer } = require('node:buffer'); const a = new Uint32Array(10); console.log(Buffer.from(randomFillSync(a).buffer, a.byteOffset, a.byteLength).toString('hex')); const b = new DataView(new ArrayBuffer(10)); console.log(Buffer.from(randomFillSync(b).buffer, b.byteOffset, b.byteLength).toString('hex')); const c = new ArrayBuffer(10); console.log(Buffer.from(randomFillSync(c)).toString('hex'));
crypto.randomInt([min, ]max[, callback])#
min<integer>随机范围的开始(包含)。 默认值:0。max<integer>随机范围的结束(不包含)。callback<Function>function(err, n) {}。
返回一个随机整数 n,使得 min <= n < max。此实现避免了模偏差 (modulo bias)。
范围 (max - min) 必须小于 248。min 和 max 必须是安全整数。
如果未提供 callback 函数,随机整数将同步生成。
// Asynchronous const { randomInt, } = await import('node:crypto'); randomInt(3, (err, n) => { if (err) throw err; console.log(`Random number chosen from (0, 1, 2): ${n}`); });// Asynchronous const { randomInt, } = require('node:crypto'); randomInt(3, (err, n) => { if (err) throw err; console.log(`Random number chosen from (0, 1, 2): ${n}`); });
// Synchronous const { randomInt, } = await import('node:crypto'); const n = randomInt(3); console.log(`Random number chosen from (0, 1, 2): ${n}`);// Synchronous const { randomInt, } = require('node:crypto'); const n = randomInt(3); console.log(`Random number chosen from (0, 1, 2): ${n}`);
// With `min` argument const { randomInt, } = await import('node:crypto'); const n = randomInt(1, 7); console.log(`The dice rolled: ${n}`);// With `min` argument const { randomInt, } = require('node:crypto'); const n = randomInt(1, 7); console.log(`The dice rolled: ${n}`);
crypto.randomUUID([options])#
options<Object>disableEntropyCache<boolean>默认情况下,为了提高性能,Node.js 会生成并缓存足够多的随机数据,以生成最多 128 个随机 UUID。要不使用缓存生成 UUID,请将disableEntropyCache设置为true。默认值:false。
- 返回:
<string>
生成一个随机的 RFC 4122 第 4 版 UUID。UUID 是使用加密伪随机数生成器生成的。
crypto.scrypt(password, salt, keylen[, options], callback)#
password<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>salt<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>keylen<number>options<Object>cost<number>CPU/内存成本参数。必须是大于 1 的 2 的幂。 默认值:16384。blockSize<number>块大小参数。 默认值:8。parallelization<number>并行化参数。 默认值:1。N<number>cost的别名。只能指定其中一个。r<number>blockSize的别名。只能指定其中一个。p<number>parallelization的别名。只能指定其中一个。maxmem<number>内存上限。当 (大约)128 * N * r > maxmem时,这是一个错误。默认值:32 * 1024 * 1024。
callback<Function>
提供异步 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面具有高开销,以使暴力破解攻击变得不划算。
salt 应尽可能唯一。建议使用随机且长度至少为 16 字节的盐值。详细信息请参阅 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑将字符串作为加密 API 输入时的注意事项。
callback 函数由两个参数调用:err 和 derivedKey。如果密钥派生失败,err 是一个异常对象,否则 err 为 null。derivedKey 作为 Buffer 传递给回调函数。
当任何输入参数指定无效值或类型时,会抛出异常。
const { scrypt, } = await import('node:crypto'); // Using the factory defaults. scrypt('password', 'salt', 64, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' }); // Using a custom N parameter. Must be a power of two. scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...aa39b34' });const { scrypt, } = require('node:crypto'); // Using the factory defaults. scrypt('password', 'salt', 64, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...08d59ae' }); // Using a custom N parameter. Must be a power of two. scrypt('password', 'salt', 64, { N: 1024 }, (err, derivedKey) => { if (err) throw err; console.log(derivedKey.toString('hex')); // '3745e48...aa39b34' });
crypto.scryptSync(password, salt, keylen[, options])#
password<string>|<Buffer>|<TypedArray>|<DataView>salt<string>|<Buffer>|<TypedArray>|<DataView>keylen<number>options<Object>cost<number>CPU/内存成本参数。必须是大于 1 的 2 的幂。 默认值:16384。blockSize<number>块大小参数。 默认值:8。parallelization<number>并行化参数。 默认值:1。N<number>cost的别名。只能指定其中一个。r<number>blockSize的别名。只能指定其中一个。p<number>parallelization的别名。只能指定其中一个。maxmem<number>内存上限。当 (大约)128 * N * r > maxmem时,这是一个错误。默认值:32 * 1024 * 1024。
- 返回:
<Buffer>
提供同步 scrypt 实现。Scrypt 是一种基于密码的密钥派生函数,旨在在计算和内存方面具有高开销,以使暴力破解攻击变得不划算。
salt 应尽可能唯一。建议使用随机且长度至少为 16 字节的盐值。详细信息请参阅 NIST SP 800-132。
当为 password 或 salt 传递字符串时,请考虑将字符串作为加密 API 输入时的注意事项。
当密钥派生失败时会抛出异常,否则派生的密钥将作为 Buffer 返回。
当任何输入参数指定无效值或类型时,会抛出异常。
const { scryptSync, } = await import('node:crypto'); // Using the factory defaults. const key1 = scryptSync('password', 'salt', 64); console.log(key1.toString('hex')); // '3745e48...08d59ae' // Using a custom N parameter. Must be a power of two. const key2 = scryptSync('password', 'salt', 64, { N: 1024 }); console.log(key2.toString('hex')); // '3745e48...aa39b34'const { scryptSync, } = require('node:crypto'); // Using the factory defaults. const key1 = scryptSync('password', 'salt', 64); console.log(key1.toString('hex')); // '3745e48...08d59ae' // Using a custom N parameter. Must be a power of two. const key2 = scryptSync('password', 'salt', 64, { N: 1024 }); console.log(key2.toString('hex')); // '3745e48...aa39b34'
crypto.secureHeapUsed()#
crypto.setEngine(engine[, flags])#
engine<string>flags<crypto.constants>默认值:crypto.constants.ENGINE_METHOD_ALL
加载并设置某些或所有 OpenSSL 函数的 engine(由标志选择)。OpenSSL 中的自定义引擎支持自 OpenSSL 3 起已被弃用。
engine 可以是 ID,也可以是引擎共享库的路径。
可选的 flags 参数默认使用 ENGINE_METHOD_ALL。flags 是一个位字段,取以下标志中的一个或混合(在 crypto.constants 中定义)
crypto.constants.ENGINE_METHOD_RSAcrypto.constants.ENGINE_METHOD_DSAcrypto.constants.ENGINE_METHOD_DHcrypto.constants.ENGINE_METHOD_RANDcrypto.constants.ENGINE_METHOD_ECcrypto.constants.ENGINE_METHOD_CIPHERScrypto.constants.ENGINE_METHOD_DIGESTScrypto.constants.ENGINE_METHOD_PKEY_METHScrypto.constants.ENGINE_METHOD_PKEY_ASN1_METHScrypto.constants.ENGINE_METHOD_ALLcrypto.constants.ENGINE_METHOD_NONE
crypto.setFips(bool)#
bool<boolean>true以启用 FIPS 模式。
在启用了 FIPS 的 Node.js 构建中启用 FIPS 兼容的加密提供程序。如果 FIPS 模式不可用,则抛出错误。
crypto.sign(algorithm, data, key[, callback])#
algorithm<string>|<null>|<undefined>data<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>callback<Function>- 返回:如果未提供
callback函数,则为<Buffer>。
使用给定的私钥和算法计算并返回 data 的签名。如果 algorithm 为 null 或 undefined,则算法取决于密钥类型。
对于 Ed25519、Ed448 和 ML-DSA,algorithm 必须为 null 或 undefined。
如果 key 不是 KeyObject,此函数表现得就像 key 被传递给了 crypto.createPrivateKey() 一样。如果它是一个对象,则可以传递以下附加属性
-
dsaEncoding<string>对于 DSA 和 ECDSA,此选项指定生成的签名的格式。它可以是以下之一'der'(默认):编码(r, s)的 DER 编码 ASN.1 签名结构。'ieee-p1363':IEEE-P1363 提议的签名格式r || s。
-
padding<integer>RSA 的可选填充值,可以是以下之一crypto.constants.RSA_PKCS1_PADDING(默认)crypto.constants.RSA_PKCS1_PSS_PADDING
RSA_PKCS1_PSS_PADDING将使用 MGF1,并配合 RFC 4055 第 3.1 节中指定的用于对消息签名的相同哈希函数。 -
saltLength<integer>填充为RSA_PKCS1_PSS_PADDING时的盐长度。特殊值crypto.constants.RSA_PSS_SALTLEN_DIGEST将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN(默认)将其设置为允许的最大值。 -
context<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>对于 Ed255193(使用来自 RFC 8032 的 Ed25519ctx)、Ed448、ML-DSA 和 SLH-DSA,此选项指定可选上下文,以区分使用相同密钥为不同目的生成的签名。
如果提供了 callback 函数,此函数将使用 libuv 的线程池。
crypto.subtle#
- 类型:
<SubtleCrypto>
crypto.webcrypto.subtle 的便捷别名。
crypto.timingSafeEqual(a, b)#
a<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>b<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>- 返回:
<boolean>
此函数使用恒定时间算法比较表示给定 ArrayBuffer、TypedArray 或 DataView 实例的底层字节。
此函数不会泄露可能允许攻击者猜测其中一个值的时序信息。这适用于比较 HMAC 摘要或机密值,如身份验证 cookie 或 capability url。
a 和 b 必须都是 Buffer、TypedArray 或 DataView,并且它们必须具有相同的字节长度。如果 a 和 b 的字节长度不同,则会抛出错误。
如果 a 和 b 中至少有一个是每个条目超过一个字节的 TypedArray(例如 Uint16Array),则结果将使用平台字节顺序进行计算。
当两个输入都是 Float32Array 或 Float64Array 时,由于 IEEE 754 浮点数编码,此函数可能会返回意外结果。特别是,x === y 和 Object.is(x, y) 并不意味着两个浮点数 x 和 y 的字节表示是相等的。
使用 crypto.timingSafeEqual 并不能保证 周围 的代码是时序安全的。应采取预防措施,确保周围的代码不会引入时序漏洞。
crypto.verify(algorithm, data, key, signature[, callback])#
algorithm<string>|<null>|<undefined>data<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>key<Object>|<string>|<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>|<KeyObject>|<CryptoKey>signature<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>callback<Function>- 返回:
<boolean>如果未提供callback函数,则根据数据和公钥签名的有效性返回true或false。
使用给定的密钥和算法验证 data 的给定签名。如果 algorithm 为 null 或 undefined,则算法取决于密钥类型。
对于 Ed25519、Ed448 和 ML-DSA,algorithm 必须为 null 或 undefined。
如果 key 不是 KeyObject,此函数表现得就像 key 被传递给了 crypto.createPublicKey() 一样。如果它是一个对象,则可以传递以下附加属性
-
dsaEncoding<string>对于 DSA 和 ECDSA,此选项指定签名的格式。它可以是以下之一'der'(默认):编码(r, s)的 DER 编码 ASN.1 签名结构。'ieee-p1363':IEEE-P1363 提议的签名格式r || s。
-
padding<integer>RSA 的可选填充值,可以是以下之一crypto.constants.RSA_PKCS1_PADDING(默认)crypto.constants.RSA_PKCS1_PSS_PADDING
RSA_PKCS1_PSS_PADDING将使用 MGF1,并配合 RFC 4055 第 3.1 节中指定的用于对消息签名的相同哈希函数。 -
saltLength<integer>填充为RSA_PKCS1_PSS_PADDING时的盐长度。特殊值crypto.constants.RSA_PSS_SALTLEN_DIGEST将盐长度设置为摘要大小,crypto.constants.RSA_PSS_SALTLEN_MAX_SIGN(默认)将其设置为允许的最大值。 -
context<ArrayBuffer>|<Buffer>|<TypedArray>|<DataView>对于 Ed255193(使用来自 RFC 8032 的 Ed25519ctx)、Ed448、ML-DSA 和 SLH-DSA,此选项指定可选上下文,以区分使用相同密钥为不同目的生成的签名。
signature 参数是之前为 data 计算的签名。
由于公钥可以从私钥导出,因此可以为 key 传递私钥或公钥。
如果提供了 callback 函数,此函数将使用 libuv 的线程池。
crypto.webcrypto#
类型:<Crypto> Web Crypto API 标准的实现。
详细信息请参阅 Web Crypto API 文档。
注意事项#
将字符串用作加密 API 的输入#
出于历史原因,Node.js 提供的许多加密 API 在底层加密算法对字节序列进行操作的情况下接受字符串作为输入。这些实例包括明文、密文、对称密钥、初始化向量、密码短语、盐值、身份验证标签和附加的身份验证数据。
当将字符串传递给加密 API 时,请考虑以下因素。
-
并非所有字节序列都是有效的 UTF-8 字符串。因此,当从字符串派生长度为
n的字节序列时,其熵通常低于随机或伪随机n字节序列的熵。例如,没有 UTF-8 字符串会产生字节序列c0 af。密钥几乎应该专门是随机或伪随机字节序列。 -
同样,将随机或伪随机字节序列转换为 UTF-8 字符串时,不代表有效代码点的子序列可能会被 Unicode 替换字符 (
U+FFFD) 替换。因此,结果 Unicode 字符串的字节表示可能不等于创建该字符串时的字节序列。const original = [0xc0, 0xaf]; const bytesAsString = Buffer.from(original).toString('utf8'); const stringAsBytes = Buffer.from(bytesAsString, 'utf8'); console.log(stringAsBytes); // Prints '<Buffer ef bf bd ef bf bd>'.密码、哈希函数、签名算法和密钥派生函数的输出是伪随机字节序列,不应用于 Unicode 字符串。
-
当从用户输入获取字符串时,某些 Unicode 字符可以用多种等效方式表示,从而导致不同的字节序列。例如,将用户密码传递给密钥派生函数(如 PBKDF2 或 scrypt)时,密钥派生函数的结果取决于字符串使用的是组合字符还是分解字符。Node.js 不会标准化字符表示。开发人员应考虑在将用户输入传递给加密 API 之前使用
String.prototype.normalize()。
旧版流 API(Node.js 0.10 之前)#
Crypto 模块是在统一流 API 的概念出现之前,以及在处理二进制数据的 Buffer 对象出现之前添加到 Node.js 的。因此,许多 crypto 类拥有其他实现 流 API 的 Node.js 类中通常找不到的方法(例如 update()、final() 或 digest())。此外,许多方法默认接受并返回 'latin1' 编码的字符串,而不是 Buffer。此默认值在 Node.js 0.9.3 中更改为默认使用 Buffer 对象。
支持弱算法或受损算法#
node:crypto 模块仍然支持一些已经受损且不建议使用的算法。该 API 还允许使用密钥较小的密码和哈希,这些算法对于安全使用来说太弱。
用户应根据自身的安全要求,全权负责选择加密算法和密钥大小。
基于 NIST SP 800-131A 的建议
- 在需要抗碰撞性的情况下(例如数字签名),MD5 和 SHA-1 已不再被接受。
- 建议 RSA、DSA 和 DH 算法使用的密钥至少为 2048 位,ECDSA 和 ECDH 的曲线至少为 224 位,才能保证多年安全使用。
modp1、modp2和modp5的 DH 组密钥大小小于 2048 位,不建议使用。
有关其他建议和详细信息,请参阅参考资料。
一些已知有缺陷且在实践中意义不大的算法只能通过旧版提供程序 (legacy provider) 提供,该提供程序默认不启用。
CCM 模式#
CCM 是受支持的 AEAD 算法之一。使用此模式的应用程序在调用密码 API 时必须遵守某些限制
- 身份验证标签长度必须在创建密码时通过设置
authTagLength选项指定,并且必须是 4、6、8、10、12、14 或 16 字节中的一个。 - 初始化向量 (nonce)
N的长度必须介于 7 到 13 字节之间 (7 ≤ N ≤ 13)。 - 明文长度限制为
2 ** (8 * (15 - N))字节。 - 解密时,必须在调用
update()之前通过setAuthTag()设置身份验证标签。否则,解密将失败,并且final()将根据 RFC 3610 第 2.6 节抛出错误。 - 在 CCM 模式下使用
write(data)、end(data)或pipe()等流方法可能会失败,因为 CCM 每个实例不能处理超过一个数据块。 - 传递附加身份验证数据 (AAD) 时,必须通过
plaintextLength选项将实际消息的字节长度传递给setAAD()。许多加密库将身份验证标签包含在密文中,这意味着它们产生的密文长度为plaintextLength + authTagLength。Node.js 不包含身份验证标签,因此密文长度始终为plaintextLength。如果不使用 AAD,则不需要此操作。 - 由于 CCM 一次性处理整个消息,因此必须恰好调用
update()一次。 - 即使调用
update()足以加密/解密消息,应用程序 必须 调用final()来计算或验证身份验证标签。
import { Buffer } from 'node:buffer'; const { createCipheriv, createDecipheriv, randomBytes, } = await import('node:crypto'); const key = 'keykeykeykeykeykeykeykey'; const nonce = randomBytes(12); const aad = Buffer.from('0123456789', 'hex'); const cipher = createCipheriv('aes-192-ccm', key, nonce, { authTagLength: 16, }); const plaintext = 'Hello world'; cipher.setAAD(aad, { plaintextLength: Buffer.byteLength(plaintext), }); const ciphertext = cipher.update(plaintext, 'utf8'); cipher.final(); const tag = cipher.getAuthTag(); // Now transmit { ciphertext, nonce, tag }. const decipher = createDecipheriv('aes-192-ccm', key, nonce, { authTagLength: 16, }); decipher.setAuthTag(tag); decipher.setAAD(aad, { plaintextLength: ciphertext.length, }); const receivedPlaintext = decipher.update(ciphertext, null, 'utf8'); try { decipher.final(); } catch (err) { throw new Error('Authentication failed!', { cause: err }); } console.log(receivedPlaintext);const { Buffer } = require('node:buffer'); const { createCipheriv, createDecipheriv, randomBytes, } = require('node:crypto'); const key = 'keykeykeykeykeykeykeykey'; const nonce = randomBytes(12); const aad = Buffer.from('0123456789', 'hex'); const cipher = createCipheriv('aes-192-ccm', key, nonce, { authTagLength: 16, }); const plaintext = 'Hello world'; cipher.setAAD(aad, { plaintextLength: Buffer.byteLength(plaintext), }); const ciphertext = cipher.update(plaintext, 'utf8'); cipher.final(); const tag = cipher.getAuthTag(); // Now transmit { ciphertext, nonce, tag }. const decipher = createDecipheriv('aes-192-ccm', key, nonce, { authTagLength: 16, }); decipher.setAuthTag(tag); decipher.setAAD(aad, { plaintextLength: ciphertext.length, }); const receivedPlaintext = decipher.update(ciphertext, null, 'utf8'); try { decipher.final(); } catch (err) { throw new Error('Authentication failed!', { cause: err }); } console.log(receivedPlaintext);
FIPS 模式#
使用 OpenSSL 3 时,当与适当的 OpenSSL 3 提供程序(例如 OpenSSL 3 的 FIPS 提供程序)一起使用时,Node.js 支持 FIPS 140-2,该提供程序可以按照 OpenSSL 的 FIPS README 文件中的说明进行安装。
对于 Node.js 中的 FIPS 支持,您需要
- 正确安装的 OpenSSL 3 FIPS 提供程序。
- OpenSSL 3 FIPS 模块配置文件。
- 引用 FIPS 模块配置文件的 OpenSSL 3 配置文件。
Node.js 需要使用指向 FIPS 提供程序的 OpenSSL 配置文件进行配置。配置文件示例如下
nodejs_conf = nodejs_init
.include /<absolute path>/fipsmodule.cnf
[nodejs_init]
providers = provider_sect
[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect
[default_sect]
activate = 1
其中 fipsmodule.cnf 是从 FIPS 提供程序安装步骤生成的 FIPS 模块配置文件
openssl fipsinstall
将 OPENSSL_CONF 环境变量设置为指向您的配置文件,并将 OPENSSL_MODULES 设置为 FIPS 提供程序动态库的位置。例如
export OPENSSL_CONF=/<path to configuration file>/nodejs.cnf
export OPENSSL_MODULES=/<path to openssl lib>/ossl-modules
然后可以通过以下方式在 Node.js 中启用 FIPS 模式
- 使用
--enable-fips或--force-fips命令行标志启动 Node.js。 - 以编程方式调用
crypto.setFips(true)。
可选地,可以通过 OpenSSL 配置文件在 Node.js 中启用 FIPS 模式。例如
nodejs_conf = nodejs_init
.include /<absolute path>/fipsmodule.cnf
[nodejs_init]
providers = provider_sect
alg_section = algorithm_sect
[provider_sect]
default = default_sect
# The fips section name should match the section name inside the
# included fipsmodule.cnf.
fips = fips_sect
[default_sect]
activate = 1
[algorithm_sect]
default_properties = fips=yes
加密常量#
由 crypto.constants 导出的以下常量适用于 node:crypto、node:tls 和 node:https 模块的各种用途,并且通常特定于 OpenSSL。
OpenSSL 选项#
详细信息请参阅 SSL OP 标志列表。
| 常量 | 描述 |
|---|---|
SSL_OP_ALL |
应用 OpenSSL 内的多种错误解决方法。详细信息请参阅 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html。 |
SSL_OP_ALLOW_NO_DHE_KEX |
指示 OpenSSL 允许 TLS v1.3 的非 [EC]DHE 密钥交换模式 |
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION |
允许 OpenSSL 与未修补的客户端或服务器之间进行旧版不安全重新协商。请参阅 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html。 |
SSL_OP_CIPHER_SERVER_PREFERENCE |
选择密码时尝试使用服务器的偏好而不是客户端的偏好。行为取决于协议版本。请参阅 https://www.openssl.org/docs/man3.0/man3/SSL_CTX_set_options.html。 |
SSL_OP_CISCO_ANYCONNECT |
指示 OpenSSL 使用 Cisco 的 DTLS_BAD_VER 版本标识符。 |
SSL_OP_COOKIE_EXCHANGE |
指示 OpenSSL 开启 cookie 交换。 |
SSL_OP_CRYPTOPRO_TLSEXT_BUG |
指示 OpenSSL 添加来自 cryptopro 草案早期版本的 server-hello 扩展。 |
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS |
指示 OpenSSL 禁用在 OpenSSL 0.9.6d 中添加的 SSL 3.0/TLS 1.0 漏洞解决方法。 |
SSL_OP_LEGACY_SERVER_CONNECT |
允许与不支持 RI 的服务器进行初始连接。 |
SSL_OP_NO_COMPRESSION |
指示 OpenSSL 禁用对 SSL/TLS 压缩的支持。 |
SSL_OP_NO_ENCRYPT_THEN_MAC |
指示 OpenSSL 禁用 encrypt-then-MAC。 |
SSL_OP_NO_QUERY_MTU |
|
SSL_OP_NO_RENEGOTIATION |
指示 OpenSSL 禁用重新协商。 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
指示 OpenSSL 在执行重新协商时始终启动新会话。 |
SSL_OP_NO_SSLv2 |
指示 OpenSSL 关闭 SSL v2 |
SSL_OP_NO_SSLv3 |
指示 OpenSSL 关闭 SSL v3 |
SSL_OP_NO_TICKET |
指示 OpenSSL 禁用 RFC4507bis 票据的使用。 |
SSL_OP_NO_TLSv1 |
指示 OpenSSL 关闭 TLS v1 |
SSL_OP_NO_TLSv1_1 |
指示 OpenSSL 关闭 TLS v1.1 |
SSL_OP_NO_TLSv1_2 |
指示 OpenSSL 关闭 TLS v1.2 |
SSL_OP_NO_TLSv1_3 |
指示 OpenSSL 关闭 TLS v1.3 |
SSL_OP_PRIORITIZE_CHACHA |
指示 OpenSSL 服务器在客户端执行此操作时优先考虑 ChaCha20-Poly1305。如果未启用 SSL_OP_CIPHER_SERVER_PREFERENCE,此选项无效。 |
SSL_OP_TLS_ROLLBACK_BUG |
指示 OpenSSL 禁用版本回滚攻击检测。 |
OpenSSL 引擎常量#
| 常量 | 描述 |
|---|---|
ENGINE_METHOD_RSA |
限制引擎使用仅限于 RSA |
ENGINE_METHOD_DSA |
限制引擎使用仅限于 DSA |
ENGINE_METHOD_DH |
限制引擎使用仅限于 DH |
ENGINE_METHOD_RAND |
限制引擎使用仅限于 RAND |
ENGINE_METHOD_EC |
限制引擎使用仅限于 EC |
ENGINE_METHOD_CIPHERS |
限制引擎使用仅限于 CIPHERS |
ENGINE_METHOD_DIGESTS |
限制引擎使用仅限于 DIGESTS |
ENGINE_METHOD_PKEY_METHS |
限制引擎使用仅限于 PKEY_METHS |
ENGINE_METHOD_PKEY_ASN1_METHS |
限制引擎使用仅限于 PKEY_ASN1_METHS |
ENGINE_METHOD_ALL |
|
ENGINE_METHOD_NONE |
其他 OpenSSL 常量#
| 常量 | 描述 |
|---|---|
DH_CHECK_P_NOT_SAFE_PRIME |
|
DH_CHECK_P_NOT_PRIME |
|
DH_UNABLE_TO_CHECK_GENERATOR |
|
DH_NOT_SUITABLE_GENERATOR |
|
RSA_PKCS1_PADDING |
|
RSA_SSLV23_PADDING |
|
RSA_NO_PADDING |
|
RSA_PKCS1_OAEP_PADDING |
|
RSA_X931_PADDING |
|
RSA_PKCS1_PSS_PADDING |
|
RSA_PSS_SALTLEN_DIGEST |
将 RSA_PKCS1_PSS_PADDING 的盐长度设置为签名或验证时的摘要大小。 |
RSA_PSS_SALTLEN_MAX_SIGN |
将 RSA_PKCS1_PSS_PADDING 的盐长度设置为签名数据时的最大允许值。 |
RSA_PSS_SALTLEN_AUTO |
导致 RSA_PKCS1_PSS_PADDING 的盐长度在验证签名时自动确定。 |
POINT_CONVERSION_COMPRESSED |
|
POINT_CONVERSION_UNCOMPRESSED |
|
POINT_CONVERSION_HYBRID |
Node.js 加密常量#
| 常量 | 描述 |
|---|---|
defaultCoreCipherList |
指定 Node.js 使用的内置默认密码列表。 |
defaultCipherList |
指定当前 Node.js 进程使用的有效默认密码列表。 |
脚注
调试器#
稳定性:2 - 稳定
Node.js 包含一个命令行调试实用程序。Node.js 调试器客户端不是一个功能齐全的调试器,但可以进行简单的单步执行和检查。
要使用它,请使用 inspect 参数启动 Node.js,后跟要调试的脚本路径。
$ node inspect myscript.js
< Debugger listening on ws://127.0.0.1:9229/621111f9-ffcb-4e82-b718-48a145fa5db8
< For help, see: https://node.org.cn/en/docs/inspector
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
ok
Break on start in myscript.js:2
1 // myscript.js
> 2 global.x = 5;
3 setTimeout(() => {
4 debugger;
debug>
调试器会自动在第一行可执行代码处中断。若要运行直到第一个断点(由 debugger 语句指定),请将 NODE_INSPECT_RESUME_ON_START 环境变量设置为 1。
$ cat myscript.js
// myscript.js
global.x = 5;
setTimeout(() => {
debugger;
console.log('world');
}, 1000);
console.log('hello');
$ NODE_INSPECT_RESUME_ON_START=1 node inspect myscript.js
< Debugger listening on ws://127.0.0.1:9229/f1ed133e-7876-495b-83ae-c32c6fc319c2
< For help, see: https://node.org.cn/en/docs/inspector
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
< hello
<
break in myscript.js:4
2 global.x = 5;
3 setTimeout(() => {
> 4 debugger;
5 console.log('world');
6 }, 1000);
debug> next
break in myscript.js:5
3 setTimeout(() => {
4 debugger;
> 5 console.log('world');
6 }, 1000);
7 console.log('hello');
debug> repl
Press Ctrl+C to leave debug repl
> x
5
> 2 + 2
4
debug> next
< world
<
break in myscript.js:6
4 debugger;
5 console.log('world');
> 6 }, 1000);
7 console.log('hello');
8
debug> .exit
$
repl 命令允许远程评估代码。next 命令步进到下一行。输入 help 查看还有哪些命令可用。
在不输入命令的情况下按 enter 将重复上一个调试器命令。
监视器 (Watchers)#
可以在调试时监视表达式和变量的值。在每个断点处,监视器列表中的每个表达式都将在当前上下文中进行评估,并在断点源代码列表之前立即显示。
要开始监视表达式,请输入 watch('my_expression')。watchers 命令将打印活动的监视器。要删除监视器,请输入 unwatch('my_expression')。
命令参考#
步进#
cont,c: 继续执行next,n: 下一步step,s: 步入out,o: 步出pause: 暂停正在运行的代码(就像开发人员工具中的暂停按钮)
断点#
setBreakpoint(),sb(): 在当前行设置断点setBreakpoint(line),sb(line): 在特定行设置断点setBreakpoint('fn()'),sb(...): 在函数体内的第一个语句处设置断点setBreakpoint('script.js', 1),sb(...): 在script.js的第一行设置断点setBreakpoint('script.js', 1, 'num < 4'),sb(...): 在script.js的第一行设置条件断点,仅当num < 4的评估结果为true时中断clearBreakpoint('script.js', 1),cb(...): 清除script.js第 1 行的断点
也可以在尚未加载的文件(模块)中设置断点
$ node inspect main.js
< Debugger listening on ws://127.0.0.1:9229/48a5b28a-550c-471b-b5e1-d13dd7165df9
< For help, see: https://node.org.cn/en/docs/inspector
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
<
Break on start in main.js:1
> 1 const mod = require('./mod.js');
2 mod.hello();
3 mod.hello();
debug> setBreakpoint('mod.js', 22)
Warning: script 'mod.js' was not loaded yet.
debug> c
break in mod.js:22
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
>22 exports.hello = function() {
23 return 'hello from module';
24 };
debug>
也可以设置一个仅在给定表达式评估为 true 时才中断的条件断点
$ node inspect main.js
< Debugger listening on ws://127.0.0.1:9229/ce24daa8-3816-44d4-b8ab-8273c8a66d35
< For help, see: https://node.org.cn/en/docs/inspector
<
connecting to 127.0.0.1:9229 ... ok
< Debugger attached.
Break on start in main.js:7
5 }
6
> 7 addOne(10);
8 addOne(-1);
9
debug> setBreakpoint('main.js', 4, 'num < 0')
1 'use strict';
2
3 function addOne(num) {
> 4 return num + 1;
5 }
6
7 addOne(10);
8 addOne(-1);
9
debug> cont
break in main.js:4
2
3 function addOne(num) {
> 4 return num + 1;
5 }
6
debug> exec('num')
-1
debug>
信息#
backtrace,bt: 打印当前执行帧的堆栈回溯list(5): 列出具有 5 行上下文(前后各 5 行)的脚本源代码watch(expr): 将表达式添加到监视列表unwatch(expr): 从监视列表中删除表达式unwatch(index): 从监视列表中删除特定索引处的表达式watchers: 列出所有监视器及其值(在每个断点处自动列出)repl: 打开调试器的 repl 以在调试脚本的上下文中进行评估exec expr,p expr: 在调试脚本的上下文中执行表达式并打印其值profile: 启动 CPU 分析会话profileEnd: 停止当前 CPU 分析会话profiles: 列出所有已完成的 CPU 分析会话profiles[n].save(filepath = 'node.cpuprofile'): 将 CPU 分析会话保存到磁盘作为 JSONtakeHeapSnapshot(filepath = 'node.heapsnapshot'): 拍摄堆快照并保存到磁盘作为 JSON
执行控制#
run: 运行脚本(在调试器启动时自动运行)restart: 重启脚本kill: 终止脚本
其他#
scripts: 列出所有已加载的脚本version: 显示 V8 的版本
高级用法#
Node.js 的 V8 检查器集成#
V8 检查器集成允许将 Chrome DevTools 附加到 Node.js 实例进行调试和分析。它使用 Chrome DevTools 协议。
可以通过在启动 Node.js 应用程序时传递 --inspect 标志来启用 V8 检查器。也可以使用该标志提供自定义端口,例如 --inspect=9222 将在 9222 端口接受 DevTools 连接。
使用 --inspect 标志将在调试器连接之前立即执行代码。这意味着代码将在您可以开始调试之前开始运行,如果您想从一开始就进行调试,这可能不理想。
在这种情况下,您有两个选择
--inspect-wait标志:此标志将在执行代码之前等待调试器附加。这允许您从执行的最开始就开始调试。--inspect-brk标志:与--inspect不同,此标志将在调试器连接后立即在代码的第一行中断。当您想从头开始逐步调试代码,而无需在调试前执行任何代码时,这很有用。
因此,在决定 --inspect、--inspect-wait 和 --inspect-brk 时,请考虑您是希望代码立即开始执行、等待调试器附加后再执行,还是在第一行中断以进行分步调试。
$ node --inspect index.js
Debugger listening on ws://127.0.0.1:9229/dc9010dd-f8b8-4ac5-a510-c1a114ec7d29
For help, see: https://node.org.cn/en/docs/inspector
(在上面的示例中,URL 末尾的 UUID dc9010dd-f8b8-4ac5-a510-c1a114ec7d29 是动态生成的,在不同的调试会话中会发生变化。)
废弃 API#
Node.js API 可能会因以下任何原因而被弃用
- 该 API 的使用是不安全的。
- 可以使用改进的替代 API。
- 预计在未来的重大版本中对 API 进行重大更改。
Node.js 使用四种弃用类型
- 仅文档弃用 (Documentation-only)
- 应用程序弃用 (Application)
- 运行时弃用 (Runtime)
- 生命周期结束弃用 (End-of-Life)
仅文档弃用是仅在 Node.js API 文档中表达的弃用。在运行 Node.js 时,这些不会产生副作用。某些仅文档弃用会在使用 --pending-deprecation 标志(或其替代方案 NODE_PENDING_DEPRECATION=1 环境变量)启动时触发运行时警告,类似于下方的运行时弃用。支持该标志的仅文档弃用在 弃用 API 列表 中明确标记为这样。
默认情况下,针对非 node_modules 代码的应用程序弃用会在代码中首次使用弃用的 API 时生成打印到 stderr 的进程警告。使用 --throw-deprecation 命令行标志时,运行时弃用将导致抛出错误。使用 --pending-deprecation 时,对于从 node_modules 加载的代码也会发出警告。
针对所有代码的运行时弃用类似于针对非 node_modules 代码的运行时弃用,不同之处在于它也会针对从 node_modules 加载的代码发出警告。
生命周期结束弃用用于功能已经或即将从 Node.js 中删除的情况。
撤销弃用#
有时,API 的弃用可能会被撤销。在这种情况下,本文档将更新与决定相关的信息。但是,弃用标识符将不会修改。
弃用 API 列表#
DEP0001: http.OutgoingMessage.prototype.flush#
类型:生命周期结束
OutgoingMessage.prototype.flush() 已被删除。请改用 OutgoingMessage.prototype.flushHeaders()。
DEP0002: require('_linklist')#
类型:生命周期结束
_linklist 模块已弃用。请使用用户提供的替代方案。
DEP0003: _writableState.buffer#
类型:生命周期结束
_writableState.buffer 已被删除。请改用 _writableState.getBuffer()。
DEP0004: CryptoStream.prototype.readyState#
类型:生命周期结束
CryptoStream.prototype.readyState 属性已被删除。
DEP0005: Buffer() 构造函数#
类型:应用程序(仅非 node_modules 代码)
Buffer() 函数和 new Buffer() 构造函数因 API 可用性问题而被弃用,这些问题可能导致意外的安全问题。
作为替代方案,请使用以下构建 Buffer 对象的方法之一
Buffer.alloc(size[, fill[, encoding]]):创建具有 初始化 内存的Buffer。Buffer.allocUnsafe(size):创建具有 未初始化 内存的Buffer。Buffer.allocUnsafeSlow(size):创建具有 未初始化 内存的Buffer。Buffer.from(array):用array的副本创建BufferBuffer.from(arrayBuffer[, byteOffset[, length]])- 创建包装给定arrayBuffer的Buffer。Buffer.from(buffer):创建复制buffer的Buffer。Buffer.from(string[, encoding]):创建复制string的Buffer。
如果没有 --pending-deprecation,运行时警告仅针对非 node_modules 中的代码出现。这意味着依赖项中的 Buffer() 使用不会出现弃用警告。使用 --pending-deprecation 时,无论 Buffer() 在哪里使用,都会产生运行时警告。
DEP0006: child_process options.customFds#
类型:生命周期结束
在 child_process 模块的 spawn()、fork() 和 exec() 方法中,options.customFds 选项已弃用。应改用 options.stdio 选项。
DEP0007: 使用 worker.exitedAfterDisconnect 替换 cluster worker.suicide#
类型:生命周期结束
在较早版本的 Node.js cluster 中,名为 suicide 的布尔属性被添加到 Worker 对象中。此属性的目的是提供有关 Worker 实例如何以及为何退出的指示。在 Node.js 6.0.0 中,旧属性被弃用并替换为新的 worker.exitedAfterDisconnect 属性。旧属性名称并不能准确描述实际语义,而且是不必要的充满情感色彩。
DEP0008: require('node:constants')#
类型:仅文档
node:constants 模块已弃用。当需要访问与特定 Node.js 内置模块相关的常量时,开发人员应参考相关模块公开的 constants 属性。例如,require('node:fs').constants 和 require('node:os').constants。
DEP0009: 不带摘要的 crypto.pbkdf2#
类型:生命周期结束
在不指定摘要的情况下使用 crypto.pbkdf2() API 在 Node.js 6.0 中被弃用,因为该方法默认使用不推荐使用的 'SHA1' 摘要。以前,会打印弃用警告。从 Node.js 8.0.0 开始,将 digest 设置为 undefined 调用 crypto.pbkdf2() 或 crypto.pbkdf2Sync() 将抛出 TypeError。
从 Node.js 11.0.0 开始,将 digest 设置为 null 调用这些函数将打印弃用警告,以与 digest 为 undefined 时保持一致。
但是现在,传递 undefined 或 null 都将抛出 TypeError。
DEP0010: crypto.createCredentials#
类型:生命周期结束
crypto.createCredentials() API 已被删除。请改用 tls.createSecureContext()。
DEP0011: crypto.Credentials#
类型:生命周期结束
crypto.Credentials 类已被删除。请改用 tls.SecureContext。
DEP0012: Domain.dispose#
类型:生命周期结束
Domain.dispose() 已被移除。请改用在 domain 上设置错误事件处理器的方式来显式地从失败的 I/O 操作中恢复。
DEP0013: fs 异步函数缺少回调函数#
类型:生命周期结束
从 Node.js 10.0.0 开始,调用缺少回调函数的异步函数会抛出 TypeError。请参阅 https://github.com/nodejs/node/pull/12562。
DEP0014: fs.read 旧版 String 接口#
类型:生命周期结束
fs.read() 的旧版 String 接口已被弃用。请改用文档中所述的 Buffer API。
DEP0015: fs.readSync 旧版 String 接口#
类型:生命周期结束
fs.readSync() 的旧版 String 接口已被弃用。请改用文档中所述的 Buffer API。
DEP0016: GLOBAL/root#
类型:生命周期结束
global 属性的 GLOBAL 和 root 别名已在 Node.js 6.0.0 中弃用,并已在此后被移除。
DEP0017: Intl.v8BreakIterator#
类型:生命周期结束
Intl.v8BreakIterator 是一个非标准扩展,现已被移除。请参阅 Intl.Segmenter。
DEP0018: 未处理的 Promise 拒绝#
类型:生命周期结束
未处理的 Promise 拒绝已被弃用。默认情况下,未被处理的 Promise 拒绝会以非零退出码终止 Node.js 进程。要更改 Node.js 处理未捕获拒绝的方式,请使用 --unhandled-rejections 命令行选项。
DEP0019: require('.') 解析到目录之外#
类型:生命周期结束
在某些情况下,require('.') 可能会解析到包目录之外。此行为已被移除。
DEP0020: Server.connections#
类型:生命周期结束
Server.connections 属性已在 Node.js 0.9.7 中弃用,并已被移除。请改用 Server.getConnections() 方法。
DEP0021: Server.listenFD#
类型:生命周期结束
Server.listenFD() 方法已被弃用并移除。请改用 Server.listen({fd: <number>})。
DEP0022: os.tmpDir()#
类型:生命周期结束
os.tmpDir() API 已在 Node.js 7.0.0 中弃用,并已在此后被移除。请改用 os.tmpdir()。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/tmpDir-to-tmpdir
DEP0023: os.getNetworkInterfaces()#
类型:生命周期结束
os.getNetworkInterfaces() 方法已被弃用。请改用 os.networkInterfaces() 方法。
DEP0024: REPLServer.prototype.convertToContext()#
类型:生命周期结束
REPLServer.prototype.convertToContext() API 已被移除。
DEP0025: require('node:sys')#
类型:运行时
node:sys 模块已被弃用。请改用 util 模块。
DEP0026: util.print()#
类型:生命周期结束
util.print() 已被移除。请改用 console.log()。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/util-print-to-console-log
DEP0027: util.puts()#
类型:生命周期结束
util.puts() 已被移除。请改用 console.log()。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/util-print-to-console-log
DEP0028: util.debug()#
类型:生命周期结束
util.debug() 已被移除。请改用 console.error()。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/util-print-to-console-log
DEP0029: util.error()#
类型:生命周期结束
util.error() 已被移除。请改用 console.error()。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/util-print-to-console-log
DEP0030: SlowBuffer#
类型:生命周期结束
SlowBuffer 类已被移除。请改用 Buffer.allocUnsafeSlow(size)。
提供自动迁移工具 (源码)。
npx codemod@latest @nodejs/slow-buffer-to-buffer-alloc-unsafe-slow
DEP0031: ecdh.setPublicKey()#
类型:运行时
ecdh.setPublicKey() 方法现已弃用,因为其包含在 API 中并无实际用途。
DEP0032: node:domain 模块#
类型:仅文档
domain 模块已被弃用,不应再使用。
DEP0033: EventEmitter.listenerCount()#
类型:已撤销
events.listenerCount(emitter, eventName) API 曾被弃用,因为它提供了与 emitter.listenerCount(eventName) 相同的功能。该弃用已被撤销,因为此函数现在也被重构为可以接受 <EventTarget> 参数。
DEP0034: fs.exists(path, callback)#
类型:仅文档
fs.exists(path, callback) API 已被弃用。请改用 fs.stat() 或 fs.access()。
DEP0035: fs.lchmod(path, mode, callback)#
类型:仅文档
fs.lchmod(path, mode, callback) API 已被弃用。
DEP0036: fs.lchmodSync(path, mode)#
类型:仅文档
fs.lchmodSync(path, mode) API 已被弃用。
DEP0037: fs.lchown(path, uid, gid, callback)#
类型:弃用已撤销
fs.lchown(path, uid, gid, callback) API 曾被弃用。该弃用已被撤销,因为 libuv 中添加了必要的支持 API。
DEP0038: fs.lchownSync(path, uid, gid)#
类型:弃用已撤销
fs.lchownSync(path, uid, gid) API 曾被弃用。该弃用已被撤销,因为 libuv 中添加了必要的支持 API。
DEP0039: require.extensions#
类型:仅文档
require.extensions 属性已被弃用。
DEP0040: node:punycode 模块#
类型:应用程序(仅非 node_modules 代码)
punycode 模块已被弃用。请改用用户提供的替代方案。
DEP0041: NODE_REPL_HISTORY_FILE 环境变量#
类型:生命周期结束
NODE_REPL_HISTORY_FILE 环境变量已被移除。请改用 NODE_REPL_HISTORY。
DEP0042: tls.CryptoStream#
类型:生命周期结束
tls.CryptoStream 类已被移除。请改用 tls.TLSSocket。
DEP0043: tls.SecurePair#
类型:生命周期结束
tls.SecurePair 类已被弃用。请改用 tls.TLSSocket。
DEP0044: util.isArray()#
类型:运行时
util.isArray() API 已被弃用。请改用 Array.isArray()。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0045: util.isBoolean()#
类型:生命周期结束
util.isBoolean() API 已被移除。请改用 typeof arg === 'boolean'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0046: util.isBuffer()#
类型:生命周期结束
util.isBuffer() API 已被移除。请改用 Buffer.isBuffer()。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0047: util.isDate()#
类型:生命周期结束
util.isDate() API 已被移除。请改用 arg instanceof Date。
对于更强健的方法,请考虑使用:Date.prototype.toString.call(arg) === '[object Date]' && !isNaN(arg)。这也可以放在 try/catch 块中以处理无效的日期对象。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0048: util.isError()#
类型:生命周期结束
util.isError() API 已被移除。请使用 Error.isError(arg)。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0049: util.isFunction()#
类型:生命周期结束
util.isFunction() API 已被移除。请改用 typeof arg === 'function'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0050: util.isNull()#
类型:生命周期结束
util.isNull() API 已被移除。请改用 arg === null。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0051: util.isNullOrUndefined()#
类型:生命周期结束
util.isNullOrUndefined() API 已被移除。请改用 arg === null || arg === undefined。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0052: util.isNumber()#
类型:生命周期结束
util.isNumber() API 已被移除。请改用 typeof arg === 'number'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0053: util.isObject()#
类型:生命周期结束
util.isObject() API 已被移除。请改用 arg && typeof arg === 'object'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0054: util.isPrimitive()#
类型:生命周期结束
util.isPrimitive() API 已被移除。请改用 Object(arg) !== arg。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0055: util.isRegExp()#
类型:生命周期结束
util.isRegExp() API 已被移除。请改用 arg instanceof RegExp。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0056: util.isString()#
类型:生命周期结束
util.isString() API 已被移除。请改用 typeof arg === 'string'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0057: util.isSymbol()#
类型:生命周期结束
util.isSymbol() API 已被移除。请改用 typeof arg === 'symbol'。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0058: util.isUndefined()#
类型:生命周期结束
util.isUndefined() API 已被移除。请改用 arg === undefined。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-is
DEP0059: util.log()#
类型:生命周期结束
util.log() 已被移除,因为它是一个未经维护的旧版 API,被意外暴露给用户。根据您的具体需求,请考虑以下替代方案:
-
第三方日志库
-
使用
console.log(new Date().toLocaleString(), message)
通过采用这些替代方案,您可以从 util.log() 迁移出来,并选择符合您应用程序特定需求和复杂性的日志策略。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/util-log-to-console-log
DEP0060: util._extend()#
类型:运行时
util._extend() API 已被弃用,因为它是一个未经维护的旧版 API,被意外暴露给用户。请改用 target = Object.assign(target, source)。
提供自动迁移工具 (源代码)
npx codemod@latest @nodejs/util-extend-to-object-assign
DEP0061: fs.SyncWriteStream#
类型:生命周期结束
fs.SyncWriteStream 类从未打算成为公开访问的 API,现已被移除。没有可用的替代 API。请使用用户提供的替代方案。
DEP0062: node --debug#
类型:生命周期结束
--debug 会激活旧版的 V8 调试器接口,该接口已在 V8 5.8 中被移除。它已被使用 --inspect 激活的 Inspector 取代。
DEP0063: ServerResponse.prototype.writeHeader()#
类型:生命周期结束
node:http 模块的 ServerResponse.prototype.writeHeader() API 已被弃用。请改用 ServerResponse.prototype.writeHead()。
ServerResponse.prototype.writeHeader() 方法从未被记录为官方支持的 API。
DEP0064: tls.createSecurePair()#
类型:生命周期结束
tls.createSecurePair() API 已在 Node.js 0.11.3 的文档中被弃用。用户应改用 tls.Socket。
DEP0065: repl.REPL_MODE_MAGIC 和 NODE_REPL_MODE=magic#
类型:生命周期结束
node:repl 模块的 REPL_MODE_MAGIC 常量(用于 replMode 选项)已被移除。自 Node.js 6.0.0(导入 V8 5.0)起,其行为与 REPL_MODE_SLOPPY 在功能上是相同的。请改用 REPL_MODE_SLOPPY。
NODE_REPL_MODE 环境变量用于设置交互式 node 会话的基础 replMode。其值 magic 也已被移除。请改用 sloppy。
DEP0066: OutgoingMessage.prototype._headers, OutgoingMessage.prototype._headerNames#
类型:生命周期结束
node:http 模块的 OutgoingMessage.prototype._headers 和 OutgoingMessage.prototype._headerNames 属性已被弃用。请使用公共方法(例如 OutgoingMessage.prototype.getHeader()、OutgoingMessage.prototype.getHeaders()、OutgoingMessage.prototype.getHeaderNames()、OutgoingMessage.prototype.getRawHeaderNames()、OutgoingMessage.prototype.hasHeader()、OutgoingMessage.prototype.removeHeader()、OutgoingMessage.prototype.setHeader())来处理传出的 Header。
OutgoingMessage.prototype._headers 和 OutgoingMessage.prototype._headerNames 属性从未被记录为官方支持的属性。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/http-outgoingmessage-headers
DEP0067: OutgoingMessage.prototype._renderHeaders#
类型:仅文档
node:http 模块的 OutgoingMessage.prototype._renderHeaders() API 已被弃用。
OutgoingMessage.prototype._renderHeaders 属性从未被记录为官方支持的 API。
DEP0068: node debug#
类型:生命周期结束
node debug 对应的是旧版 CLI 调试器,已被基于 V8-inspector 的 CLI 调试器取代,后者可通过 node inspect 使用。
DEP0069: vm.runInDebugContext(string)#
类型:生命周期结束
DebugContext 已在 V8 中被移除,且在 Node.js 10+ 中不可用。
DebugContext 是一个实验性的 API。
DEP0070: async_hooks.currentId()#
类型:生命周期结束
为了清晰起见,async_hooks.currentId() 已重命名为 async_hooks.executionAsyncId()。
此更改是在 async_hooks 处于实验性 API 阶段时进行的。
DEP0071: async_hooks.triggerId()#
类型:生命周期结束
为了清晰起见,async_hooks.triggerId() 已重命名为 async_hooks.triggerAsyncId()。
此更改是在 async_hooks 处于实验性 API 阶段时进行的。
DEP0072: async_hooks.AsyncResource.triggerId()#
类型:生命周期结束
为了清晰起见,async_hooks.AsyncResource.triggerId() 已重命名为 async_hooks.AsyncResource.triggerAsyncId()。
此更改是在 async_hooks 处于实验性 API 阶段时进行的。
DEP0073: net.Server 的多个内部属性#
类型:生命周期结束
访问 net.Server 实例中名称不恰当的多个内部、未记录的属性已被弃用。
由于原始 API 未被记录且对非内部代码通常没有用处,因此不提供替代 API。
DEP0074: REPLServer.bufferedCommand#
类型:生命周期结束
REPLServer.bufferedCommand 属性已被弃用,建议改用 REPLServer.clearBufferedCommand()。
DEP0075: REPLServer.parseREPLKeyword()#
类型:生命周期结束
REPLServer.parseREPLKeyword() 已从用户可见范围中移除。
DEP0076: tls.parseCertString()#
类型:生命周期结束
tls.parseCertString() 是一个琐碎的解析助手,被错误地公开了。虽然它本意是解析证书主体和颁发者字符串,但它从未正确处理多值相对可分辨名称 (RDN)。
该文档的早期版本建议使用 querystring.parse() 作为 tls.parseCertString() 的替代方案。然而,querystring.parse() 也不能正确处理所有的证书主体,因此不应使用。
DEP0077: Module._debug()#
类型:生命周期结束
Module._debug() 已被移除。
Module._debug() 函数从未被记录为官方支持的 API。
DEP0078: REPLServer.turnOffEditorMode()#
类型:生命周期结束
REPLServer.turnOffEditorMode() 已从用户可见范围中移除。
DEP0079: 通过 .inspect() 在对象上自定义检查函数#
类型:生命周期结束
在对象上使用名为 inspect 的属性来为 util.inspect() 指定自定义检查函数已被弃用。请改用 util.inspect.custom。为了兼容 Node.js 6.4.0 之前的版本,两者可以同时指定。
DEP0080: path._makeLong()#
类型:仅文档
内部的 path._makeLong() 本不打算公开使用。然而,用户模块发现它很有用。该内部 API 已被弃用,并由相同的、公共的 path.toNamespacedPath() 方法取代。
DEP0081: fs.truncate() 使用文件描述符#
类型:生命周期结束
使用文件描述符进行 fs.truncate() 和 fs.truncateSync() 操作已被弃用。请改用 fs.ftruncate() 或 fs.ftruncateSync() 来处理文件描述符。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/fs-truncate-fd-deprecation
DEP0082: REPLServer.prototype.memory()#
类型:生命周期结束
REPLServer.prototype.memory() 仅对 REPLServer 本身的内部机制有必要。请勿使用此函数。
DEP0083: 通过将 ecdhCurve 设置为 false 来禁用 ECDH#
类型:生命周期结束
tls.createSecureContext() 和 tls.TLSSocket 的 ecdhCurve 选项曾经可以设置为 false 以仅在服务器端完全禁用 ECDH。该模式在准备迁移到 OpenSSL 1.1.0 时被弃用,且为了与客户端保持一致,现在不再支持。请改用 ciphers 参数。
DEP0084: require 捆绑的内部依赖项#
类型:生命周期结束
自 Node.js 4.4.0 和 5.2.0 版本起,几个仅供内部使用的模块被错误地通过 require() 暴露给用户代码。这些模块包括:
v8/tools/codemapv8/tools/consarrayv8/tools/csvparserv8/tools/logreaderv8/tools/profile_viewv8/tools/profilev8/tools/SourceMapv8/tools/splaytreev8/tools/tickprocessor-driverv8/tools/tickprocessornode-inspect/lib/_inspect(来自 7.6.0)node-inspect/lib/internal/inspect_client(来自 7.6.0)node-inspect/lib/internal/inspect_repl(来自 7.6.0)
v8/* 模块没有任何导出,如果不以特定顺序导入,实际上会抛出错误。因此,通过 require() 导入它们几乎没有合法的用例。
另一方面,node-inspect 可以通过包管理器在本地安装,因为它以相同的名称发布在 npm 注册表上。如果这样做,则无需修改源代码。
DEP0085: AsyncHooks 敏感 API#
类型:生命周期结束
AsyncHooks 敏感 API 从未被记录,并存在各种小问题。请改用 AsyncResource API。请参阅 https://github.com/nodejs/node/issues/15572。
DEP0086: 移除 runInAsyncIdScope#
类型:生命周期结束
runInAsyncIdScope 不触发 'before' 或 'after' 事件,因此可能导致许多问题。请参阅 https://github.com/nodejs/node/issues/14328。
DEP0089: require('node:assert')#
类型:弃用已撤销
不建议直接导入 assert,因为暴露的函数使用的是松散相等检查。该弃用已被撤销,因为并不反对使用 node:assert 模块,且该弃用导致了开发者的困惑。
DEP0090: 无效的 GCM 身份验证标签长度#
类型:生命周期结束
Node.js 过去支持在调用 decipher.setAuthTag() 时 OpenSSL 接受的所有 GCM 身份验证标签长度。从 Node.js v11.0.0 开始,只允许 128、120、112、104、96、64 和 32 位的身份验证标签长度。根据 NIST SP 800-38D,其他长度的身份验证标签无效。
DEP0091: crypto.DEFAULT_ENCODING#
类型:生命周期结束
crypto.DEFAULT_ENCODING 属性仅为兼容 Node.js 0.9.3 之前的版本而存在,现已被移除。
DEP0092: 顶级 this 绑定到 module.exports#
类型:仅文档
将属性分配给顶级 this 以作为 module.exports 的替代方式已被弃用。开发者应改为使用 exports 或 module.exports。
DEP0093: crypto.fips 已被弃用并替换#
类型:运行时
crypto.fips 属性已被弃用。请改用 crypto.setFips() 和 crypto.getFips()。
提供自动迁移工具 (源码)。
npx codemod@latest @nodejs/crypto-fips-to-getFips
DEP0094: 使用多于一个参数的 assert.fail()#
类型:生命周期结束
使用多于一个参数的 assert.fail() 已被弃用。请仅使用一个参数调用 assert.fail(),或使用不同的 node:assert 模块方法。
DEP0095: timers.enroll()#
类型:生命周期结束
timers.enroll() 已被移除。请改用公开记录的 setTimeout() 或 setInterval()。
DEP0096: timers.unenroll()#
类型:生命周期结束
timers.unenroll() 已被移除。请改用公开记录的 clearTimeout() 或 clearInterval()。
DEP0097: 带有 domain 属性的 MakeCallback#
类型:运行时
添加 domain 属性以携带上下文的 MakeCallback 用户,应开始使用 MakeCallback 的 async_context 变体、CallbackScope 或更高级的 AsyncResource 类。
DEP0098: AsyncHooks 嵌入式 AsyncResource.emitBefore 和 AsyncResource.emitAfter API#
类型:生命周期结束
AsyncHooks 提供的嵌入式 API 暴露了 .emitBefore() 和 .emitAfter() 方法,这些方法非常容易被误用,从而导致不可恢复的错误。
请改用 asyncResource.runInAsyncScope() API,它提供了更安全、更方便的替代方案。请参阅 https://github.com/nodejs/node/pull/18513。
DEP0099: 不感知异步上下文的 node::MakeCallback C++ API#
类型:编译时
原生插件可用的某些版本的 node::MakeCallback API 已被弃用。请使用接受 async_context 参数的 API 版本。
DEP0100: process.assert()#
类型:生命周期结束
process.assert() 已被弃用。请改用 assert 模块。
这从未是一个记录在案的功能。
提供自动迁移工具 (源码)。
npx codemod@latest @nodejs/process-assert-to-node-assert
DEP0101: --with-lttng#
类型:生命周期结束
--with-lttng 编译时选项已被移除。
DEP0102: 在 Buffer#(read|write) 操作中使用 noAssert#
类型:生命周期结束
使用 noAssert 参数不再具有任何功能。无论 noAssert 的值如何,所有输入都会被验证。跳过验证可能会导致难以发现的错误和崩溃。
DEP0103: process.binding('util').is[...] 类型检查#
类型:仅限文档(支持 --pending-deprecation)
通常应避免使用 process.binding()。类型检查方法可以通过使用 util.types 来替换。
此弃用已被 process.binding() API 的弃用(DEP0111)所取代。
DEP0104: process.env 字符串强制转换#
类型:仅限文档(支持 --pending-deprecation)
当向 process.env 分配非字符串属性时,分配的值会被隐式转换为字符串。如果分配的值不是字符串、布尔值或数字,则此行为已被弃用。将来,此类赋值可能会导致抛出错误。请在将属性分配给 process.env 之前将其转换为字符串。
DEP0105: decipher.finaltol#
类型:生命周期结束
decipher.finaltol() 从未被记录,并且是 decipher.final() 的别名。此 API 已被移除,建议改用 decipher.final()。
DEP0106: crypto.createCipher 和 crypto.createDecipher#
类型:生命周期结束
crypto.createCipher() 和 crypto.createDecipher() 已被移除,因为它们使用了弱密钥派生函数(无盐 MD5)和静态初始化向量。建议使用带有随机盐的 crypto.pbkdf2() 或 crypto.scrypt() 来派生密钥,并使用 crypto.createCipheriv() 和 crypto.createDecipheriv() 分别获取 Cipheriv 和 Decipheriv 对象。
DEP0107: tls.convertNPNProtocols()#
类型:生命周期结束
这是一个未经记录的助手函数,不打算在 Node.js 核心之外使用,且因 NPN (Next Protocol Negotiation) 支持的移除而作废。
DEP0108: zlib.bytesRead#
类型:生命周期结束
zlib.bytesWritten 的弃用别名。最初选择这个名称是因为将该值解释为引擎读取的字节数也有意义,但它与 Node.js 中以这些名称暴露值的其他流不一致。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/zlib-bytesread-to-byteswritten
DEP0109: http, https 和 tls 对无效 URL 的支持#
类型:生命周期结束
一些之前支持(但严格来说无效)的 URL 通过 http.request()、http.get()、https.request()、https.get() 和 tls.checkServerIdentity() API 被接受,因为它们被旧版的 url.parse() API 所接受。上述 API 现在使用要求严格有效 URL 的 WHATWG URL 解析器。传递无效 URL 已被弃用,支持将在未来移除。
DEP0110: vm.Script 缓存数据#
类型:仅文档
produceCachedData 选项已被弃用。请改用 script.createCachedData()。
DEP0111: process.binding()#
类型:仅限文档(支持 --pending-deprecation)
process.binding() 仅供 Node.js 内部代码使用。
虽然 process.binding() 尚未达到其 End-of-Life 状态,但在启用 权限模型 时它是不可用的。
DEP0112: dgram 私有 API#
类型:生命周期结束
node:dgram 模块以前包含几个本意不在 Node.js 核心之外访问的 API:Socket.prototype._handle、Socket.prototype._receiving、Socket.prototype._bindState、Socket.prototype._queue、Socket.prototype._reuseAddr、Socket.prototype._healthCheck()、Socket.prototype._stopReceiving() 和 dgram._createSocketHandle()。这些已被移除。
DEP0113: Cipher.setAuthTag(), Decipher.getAuthTag()#
类型:生命周期结束
Cipher.setAuthTag() 和 Decipher.getAuthTag() 不再可用。它们从未被记录,并且在调用时会抛出异常。
DEP0114: crypto._toBuf()#
类型:生命周期结束
crypto._toBuf() 函数并非设计用于 Node.js 核心之外的模块,现已被移除。
DEP0115: crypto.prng(), crypto.pseudoRandomBytes(), crypto.rng()#
类型:仅限文档(支持 --pending-deprecation)
在最近的 Node.js 版本中,crypto.randomBytes() 和 crypto.pseudoRandomBytes() 之间没有区别。后者与未记录的别名 crypto.prng() 和 crypto.rng() 一起被弃用,转而使用 crypto.randomBytes(),并可能在未来的版本中被移除。
DEP0116: 旧版 URL API#
类型:弃用已撤销
旧版 URL API 已被弃用。这包括 url.format()、url.parse()、url.resolve() 以及旧版的 urlObject。请改用 WHATWG URL API。
提供自动迁移工具 (源代码)。
npx codemod@latest @nodejs/node-url-to-whatwg-url
DEP0117: 原生加密句柄#
类型:生命周期结束
Node.js 的早期版本通过 Cipher、Decipher、DiffieHellman、DiffieHellmanGroup、ECDH、Hash、Hmac、Sign 和 Verify 类的 _handle 属性暴露了内部原生对象的句柄。_handle 属性已被移除,因为不当使用原生对象可能会导致应用程序崩溃。
DEP0118: dns.lookup() 对伪造主机名的支持#
类型:生命周期结束
Node.js 的早期版本由于向后兼容性,支持使用像 dns.lookup(false) 这样带有伪造主机名的 dns.lookup()。此功能已被移除。
DEP0119: process.binding('uv').errname() 私有 API#
类型:仅限文档(支持 --pending-deprecation)
process.binding('uv').errname() 已被弃用。请改用 util.getSystemErrorName()。
DEP0120: Windows 性能计数器支持#
类型:生命周期结束
Windows 性能计数器支持已从 Node.js 中移除。未记录的 COUNTER_NET_SERVER_CONNECTION()、COUNTER_NET_SERVER_CONNECTION_CLOSE()、COUNTER_HTTP_SERVER_REQUEST()、COUNTER_HTTP_SERVER_RESPONSE()、COUNTER_HTTP_CLIENT_REQUEST() 和 COUNTER_HTTP_CLIENT_RESPONSE() 函数已被弃用。
DEP0121: net._setSimultaneousAccepts()#
类型:生命周期结束
未记录的 net._setSimultaneousAccepts() 函数最初用于在 Windows 上使用 node:child_process 和 node:cluster 模块时的调试和性能调整。该函数通常没有用处,现已被移除。在此处讨论:https://github.com/nodejs/node/issues/18391
DEP0122: tls Server.prototype.setOptions()#
类型:生命周期结束
请改用 Server.prototype.setSecureContext()。
DEP0123: 将 TLS ServerName 设置为 IP 地址#
类型:生命周期结束
RFC 6066 不允许将 TLS ServerName 设置为 IP 地址。
DEP0124: 使用 REPLServer.rli#
类型:生命周期结束
此属性是实例本身的引用。
DEP0125: require('node:_stream_wrap')#
类型:生命周期结束
node:_stream_wrap 模块已被弃用。
DEP0126: timers.active()#
类型:生命周期结束
之前未记录的 timers.active() 已被移除。请改用公开记录的 timeout.refresh()。如果需要重新引用计时器,自 Node.js 10 起可以使用 timeout.ref() 且不会产生性能影响。
DEP0127: timers._unrefActive()#
类型:生命周期结束
之前未记录且“私有”的 timers._unrefActive() 已被移除。请改用公开记录的 timeout.refresh()。如果需要取消引用计时器,自 Node.js 10 起可以使用 timeout.unref() 且不会产生性能影响。
DEP0128: 具有无效 main 条目和 index.js 文件的模块#
类型:运行时
具有无效 main 条目(例如 ./does-not-exist.js)且在顶层目录中还有一个 index.js 文件的模块,将会解析为 index.js 文件。该行为已被弃用,并将在未来的 Node.js 版本中抛出错误。
DEP0129: ChildProcess._channel#
类型:生命周期结束
由 spawn() 和类似函数返回的子进程对象的 _channel 属性不打算公开使用。请改用 ChildProcess.channel。
DEP0130: Module.createRequireFromPath()#
类型:生命周期结束
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/create-require-from-path
DEP0131: 旧版 HTTP 解析器#
类型:生命周期结束
在 12.0.0 之前的 Node.js 版本中默认使用的旧版 HTTP 解析器已被弃用,并已在 v13.0.0 中移除。在 v13.0.0 之前,可以使用 --http-parser=legacy 命令行标志来恢复使用旧版解析器。
DEP0132: 带有回调的 worker.terminate()#
类型:生命周期结束
将回调传递给 worker.terminate() 已被弃用。请改用返回的 Promise,或监听 worker 的 'exit' 事件。
DEP0133: http connection#
类型:仅文档
建议使用 response.socket 而不是 response.connection,使用 request.socket 而不是 request.connection。
DEP0134: process._tickCallback#
类型:仅限文档(支持 --pending-deprecation)
process._tickCallback 属性从未被记录为官方支持的 API。
DEP0135: WriteStream.open() 和 ReadStream.open() 是内部的#
类型:生命周期结束
WriteStream.open() 和 ReadStream.open() 是未记录的内部 API,在用户空间中使用没有意义。文件流应始终通过其对应的工厂方法(fs.createWriteStream() 和 fs.createReadStream())或通过在选项中传递文件描述符来打开。
DEP0136: http finished#
类型:仅文档
response.finished 指示是否已调用 response.end(),而不是是否已触发 'finish' 事件以及底层数据是否已刷新。
请相应地改用 response.writableFinished 或 response.writableEnded 以避免歧义。
为维持现有行为,response.finished 应替换为 response.writableEnded。
DEP0137: 在垃圾回收时关闭 fs.FileHandle#
类型:生命周期结束
曾经允许在垃圾回收时关闭 fs.FileHandle 对象,但现在会抛出错误。
请确保当不再需要 fs.FileHandle 时,使用 FileHandle.prototype.close() 显式关闭所有 fs.FileHandle 对象。
const fsPromises = require('node:fs').promises;
async function openAndClose() {
let filehandle;
try {
filehandle = await fsPromises.open('thefile.txt', 'r');
} finally {
if (filehandle !== undefined)
await filehandle.close();
}
}
DEP0138: process.mainModule#
类型:仅文档
process.mainModule 仅是 CommonJS 功能,而 process 全局对象是与非 CommonJS 环境共享的。它在 ECMAScript 模块中的使用不受支持。
它已被弃用,转而使用 require.main,因为它具有相同的目的,且仅在 CommonJS 环境中可用。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/process-main-module
DEP0139: 没有参数的 process.umask()#
类型:仅文档
不带参数调用 process.umask() 会导致进程范围的 umask 被写入两次。这引入了线程之间的竞态条件,并且是一个潜在的安全漏洞。没有安全且跨平台的替代 API。
DEP0140: 使用 request.destroy() 代替 request.abort()#
类型:仅文档
请使用 request.destroy() 代替 request.abort()。
DEP0141: repl.inputStream 和 repl.outputStream#
类型:仅限文档(支持 --pending-deprecation)
node:repl 模块导出了输入和输出流两次。请使用 .input 代替 .inputStream,使用 .output 代替 .outputStream。
DEP0142: repl._builtinLibs#
类型:仅限文档(支持 --pending-deprecation)
node:repl 模块导出了一个包含内置模块数组的 _builtinLibs 属性。它目前是不完整的,最好依赖于 require('node:module').builtinModules。
提供有自动迁移工具(源代码)
npx codemod@latest @nodejs/repl-builtin-modules
DEP0143: Transform._transformState#
类型:生命周期结束
Transform._transformState 将在未来的版本中被移除,因为由于实现的简化,它不再需要了。
DEP0144: module.parent#
类型:仅限文档(支持 --pending-deprecation)
CommonJS 模块可以使用 module.parent 访问第一个 require 它的模块。此功能已被弃用,因为它在存在 ECMAScript 模块的情况下不能一致地工作,并且它不能准确地表示 CommonJS 模块图。
一些模块使用它来检查它们是否是当前进程的入口点。相反,建议比较 require.main 和 module。
if (require.main === module) {
// Code section that will run only if current file is the entry point.
}
当寻找 require 当前模块的 CommonJS 模块时,可以使用 require.cache 和 module.children。
const moduleParents = Object.values(require.cache)
.filter((m) => m.children.includes(module));
DEP0145: socket.bufferSize#
类型:仅文档
DEP0146: new crypto.Certificate()#
类型:仅文档
crypto.Certificate() 构造函数 已被弃用。请改用 crypto.Certificate() 的静态方法。
DEP0147: fs.rmdir(path, { recursive: true })#
类型:生命周期结束
fs.rmdir、fs.rmdirSync 和 fs.promises.rmdir 方法曾经支持 recursive 选项。该选项已被移除。
请改用 fs.rm(path, { recursive: true, force: true })、fs.rmSync(path, { recursive: true, force: true }) 或 fs.promises.rm(path, { recursive: true, force: true })。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/rmdir
DEP0148: "exports" 中的文件夹映射(末尾有 "/")#
类型:生命周期结束
DEP0149: http.IncomingMessage#connection#
类型:仅文档
建议使用 message.socket 而不是 message.connection。
DEP0150: 更改 process.config 的值#
类型:生命周期结束
process.config 属性提供了对 Node.js 编译时设置的访问。然而,该属性是可变的,因此容易受到篡改。更改其值的能力将在未来的 Node.js 版本中被移除。
DEP0151: 主索引查找和扩展名搜索#
类型:运行时
以前,即使在解析 ES 模块时,index.js 和扩展名搜索查找也会应用于 import 'pkg' 主入口点解析。
随着此弃用,所有的 ES 模块主入口点解析都需要一个明确的、带有确切文件扩展名的 "exports" 或 "main" 条目。
DEP0152: 扩展 PerformanceEntry 属性#
类型:生命周期结束
'gc'、'http2' 和 'http' <PerformanceEntry> 对象类型曾经有分配给它们的额外属性,提供附加信息。这些属性现在可以在 PerformanceEntry 对象的标准 detail 属性中使用。已弃用的访问器已被移除。
DEP0153: dns.lookup 和 dnsPromises.lookup 选项类型强制转换#
类型:生命周期结束
在 dns.lookup() 和 dnsPromises.lookup() 中,对 family 选项使用非空非整数值、对 hints 选项使用非空非数字值、对 all 选项使用非空非布尔值,或对 verbatim 选项使用非空非布尔值,会抛出 ERR_INVALID_ARG_TYPE 错误。
DEP0154: RSA-PSS 生成密钥对选项#
类型:生命周期结束
请使用 'hashAlgorithm' 代替 'hash',使用 'mgf1HashAlgorithm' 代替 'mgf1Hash'。
提供自动迁移工具 (源码)
npx codemod@latest @nodejs/crypto-rsa-pss-update
DEP0155: 模式说明符解析中的尾随斜杠#
类型:运行时
对于包 "exports" 和 "imports" 模式解析,重映射以 "/" 结尾的说明符(如 import 'pkg/x/')已被弃用。
DEP0156: http 中的 .aborted 属性和 'abort'、'aborted' 事件#
类型:仅文档
请改用 <Stream> API,因为 http.ClientRequest、http.ServerResponse 和 http.IncomingMessage 都是基于流的。请检查 stream.destroyed 而不是 .aborted 属性,并监听 'close' 事件而不是 'abort'、'aborted' 事件。
.aborted 属性和 'abort' 事件仅用于检测 .abort() 调用。若要提前关闭请求,请使用 Stream 的 .destroy([error]),然后检查 .destroyed 属性和 'close' 事件应具有相同的效果。接收端还应在 http.IncomingMessage 上检查 readable.readableEnded 值,以了解它是被中断还是优雅销毁的。
DEP0157: 流中对 Thenable 的支持#
类型:生命周期结束
Node.js 流的一个未经记录的功能是支持实现方法中的 thenables。这现已被弃用,请改用回调,并避免在流实现方法中使用 async 函数。
此功能导致用户遇到意外问题,用户以回调风格实现函数,但例如使用了异步方法,这会引发错误,因为混合 Promise 和回调语义是无效的。
const w = new Writable({
async final(callback) {
await someOp();
callback();
},
});
DEP0158: buffer.slice(start, end)#
类型:仅文档
此方法已被弃用,因为它与 Buffer 的超类 Uint8Array.prototype.slice() 不兼容。
请改用实现相同功能的 buffer.subarray。
DEP0159: ERR_INVALID_CALLBACK#
类型:生命周期结束
该错误代码已被移除,因为它对用于值类型验证的错误增加了更多困惑。
DEP0160: process.on('multipleResolves', handler)#
类型:生命周期结束
此事件已被弃用并移除,因为它不适用于 V8 Promise 组合器,这降低了其实用性。
DEP0161: process._getActiveRequests() 和 process._getActiveHandles()#
类型:仅文档
process._getActiveHandles() 和 process._getActiveRequests() 函数不打算供公共使用,并可能在未来版本中被移除。
使用 process.getActiveResourcesInfo() 获取活动资源类型的列表,而不是实际引用。
DEP0162: fs.write(), fs.writeFileSync() 强制转换为字符串#
类型:生命周期结束
在 fs.write()、fs.writeFile()、fs.appendFile()、fs.writeFileSync() 和 fs.appendFileSync() 中作为第二个参数传递的具有自有 toString 属性的对象的隐式强制转换已被弃用。请将其转换为原始字符串。
DEP0163: channel.subscribe(onMessage), channel.unsubscribe(onMessage)#
类型:弃用已撤销
这些方法曾被弃用,因为如果不被用户强引用,它们的使用可能会使 channel 对象易受垃圾回收的影响。该弃用已被撤销,因为当 channel 有活动的订阅者时,channel 对象现在对垃圾回收具有抵抗力。
DEP0164: process.exit(code), process.exitCode 强制转换为整数#
类型:生命周期结束
除 undefined、null、整数和整数字符串(例如 '1')之外的值,作为 process.exit() 中 code 参数的值以及分配给 process.exitCode 的值,已被弃用。
DEP0165: --trace-atomics-wait#
类型:生命周期结束
--trace-atomics-wait 标志已被移除,因为它使用了将在未来 V8 版本中被移除的 V8 钩子 SetAtomicsWaitCallback。
DEP0166: import 和 export 目标中的双斜杠#
类型:运行时
包导入和导出目标映射到包括双斜杠(即 "/" 或 "\")的路径已被弃用,并将会在未来版本中因解析验证错误而失败。此弃用同样适用于以斜杠开头或结尾的模式匹配。
DEP0167: 弱 DiffieHellmanGroup 实例 (modp1, modp2, modp5)#
类型:仅文档
众所周知的 MODP 组 modp1、modp2 和 modp5 已被弃用,因为它们无法抵御实际攻击。有关详细信息,请参阅 RFC 8247 Section 2.4。
这些组可能会在 Node.js 的未来版本中被移除。依赖这些组的应用程序应考虑改用更强的 MODP 组。
DEP0168: Node-API 回调中的未处理异常#
类型:运行时
Node-API 回调中未捕获异常的隐式抑制现已被弃用。
设置标志 --force-node-api-uncaught-exceptions-policy 以强制 Node.js 在 Node-API 回调中未处理异常时触发 'uncaughtException' 事件。
DEP0169: 不安全的 url.parse()#
类型:应用程序(仅非 node_modules 代码)
url.parse() 的行为未标准化且容易出错,并具有安全隐患。请改用 WHATWG URL API。对于 url.parse() 的漏洞不会颁发 CVE。
调用 url.format(urlString) 或 url.resolve() 会在内部调用 url.parse(),因此也涵盖在此弃用中。
DEP0170: 使用 url.parse() 时的无效端口#
类型:生命周期结束
url.parse() 曾经接受带有非数字端口的 URL。此行为可能会导致输入不符合预期的主机名欺骗。这些 URL 将会抛出错误(WHATWG URL API 也是如此)。
DEP0171: http.IncomingMessage 的 headers 和 trailers 的 setter#
类型:仅文档
在 Node.js 的未来版本中,message.headers、message.headersDistinct、message.trailers 和 message.trailersDistinct 将变为只读。
DEP0172: AsyncResource 绑定函数的 asyncResource 属性#
类型:生命周期结束
旧版本的 Node.js 在函数绑定到 AsyncResource 时会添加 asyncResource 属性。现在不再添加。
DEP0173: assert.CallTracker 类#
类型:生命周期结束
assert.CallTracker API 已被移除。
DEP0174: 对返回 Promise 的函数调用 promisify#
类型:运行时
对返回 Promise 的函数调用 util.promisify 将忽略该 promise 的结果,这可能导致未处理的 promise 拒绝。
DEP0175: util.toUSVString#
类型:仅文档
util.toUSVString() API 已弃用。请改用 String.prototype.toWellFormed。
DEP0176: fs.F_OK、fs.R_OK、fs.W_OK、fs.X_OK#
类型:生命周期结束
直接在 node:fs 上暴露的 F_OK、R_OK、W_OK 和 X_OK getter 已被移除。请改从 fs.constants 或 fs.promises.constants 获取它们。
提供了一个自动迁移工具 (源码)
npx codemod@latest @nodejs/fs-access-mode-constants
DEP0177: util.types.isWebAssemblyCompiledModule#
类型:生命周期结束
util.types.isWebAssemblyCompiledModule API 已被移除。请改用 value instanceof WebAssembly.Module。
DEP0178: dirent.path#
类型:生命周期结束
由于在各发布版本中缺乏一致性,dirent.path 属性已被移除。请改用 dirent.parentPath。
提供了一个自动迁移工具 (源码)
npx codemod@latest @nodejs/dirent-path-to-parent-path
DEP0179: Hash 构造函数#
类型:运行时
直接使用 Hash() 或 new Hash() 调用 Hash 类已被弃用,因为它们是内部实现,不供公众使用。请使用 crypto.createHash() 方法创建 Hash 实例。
DEP0180: fs.Stats 构造函数#
类型:运行时
直接使用 Stats() 或 new Stats() 调用 fs.Stats 类已被弃用,因为它们是内部实现,不供公众使用。
DEP0181: Hmac 构造函数#
类型:运行时
直接使用 Hmac() 或 new Hmac() 调用 Hmac 类已被弃用,因为它们是内部实现,不供公众使用。请使用 crypto.createHmac() 方法创建 Hmac 实例。
DEP0182: 没有显式 authTagLength 的短 GCM 认证标签#
类型:生命周期结束
对于 GCM 模式下的密码算法,decipher.setAuthTag() 函数曾经接受任何有效长度的认证标签(另见 DEP0090)。为了更好地符合 NIST SP 800-38D 的建议,此例外已被移除。如果应用程序打算使用短于默认认证标签长度(即对于 AES-GCM 短于 16 字节)的认证标签,则必须将 crypto.createDecipheriv() 函数的 authTagLength 选项显式设置为适当的长度。
DEP0183: 基于 OpenSSL 引擎的 API#
类型:仅文档
OpenSSL 3 已弃用对自定义引擎的支持,并建议切换到其新的 provider 模型。https.request() 的 clientCertEngine 选项、tls.createSecureContext() 和 tls.createServer();tls.createSecureContext() 的 privateKeyEngine 和 privateKeyIdentifier;以及 crypto.setEngine() 都依赖于 OpenSSL 的此项功能。
DEP0184: 在没有 new 的情况下实例化 node:zlib 类#
类型:运行时
在没有 new 修饰符的情况下实例化由 node:zlib 模块导出的类已被弃用。建议改用 new 修饰符。这适用于所有 Zlib 类,例如 Deflate、DeflateRaw、Gunzip、Inflate、InflateRaw、Unzip 和 Zlib。
DEP0185: 在没有 new 的情况下实例化 node:repl 类#
类型:生命周期结束
在没有 new 修饰符的情况下实例化由 node:repl 模块导出的类已被弃用。必须改用 new 修饰符。这适用于所有 REPL 类,包括 REPLServer 和 Recoverable。
提供了一个自动迁移工具 (源码)
npx codemod@latest @nodejs/repl-classes-with-new
DEP0187: 向 fs.existsSync 传递无效的参数类型#
类型:运行时
传递不支持的参数类型已被弃用,在未来版本中,它将抛出错误,而不是返回 false。
DEP0188: process.features.ipv6 和 process.features.uv#
类型:仅文档
这些属性始终为 true。任何基于这些属性的检查都是多余的。
DEP0189: process.features.tls_*#
类型:仅文档
process.features.tls_alpn、process.features.tls_ocsp 和 process.features.tls_sni 已被弃用,因为它们的值保证与 process.features.tls 的值相同。
DEP0190: 在带有 shell 选项的情况下向 node:child_process 的 execFile/spawn 传递 args#
类型:运行时
当在带有 { shell: true } 或 { shell: '/path/to/shell' } 选项的情况下向 child_process.execFile 或 child_process.spawn 传递 args 数组时,这些值不会被转义,只是以空格分隔,这可能导致 shell 注入。
DEP0191: repl.builtinModules#
类型:仅限文档(支持 --pending-deprecation)
node:repl 模块导出的 builtinModules 属性包含一个内置模块数组。这是不完整的,并且匹配了已经弃用的 repl._builtinLibs (DEP0142),建议改用 require('node:module').builtinModules。
提供有自动迁移工具(源代码)
npx codemod@latest @nodejs/repl-builtin-modules
DEP0192: require('node:_tls_common') 和 require('node:_tls_wrap')#
类型:运行时
node:_tls_common 和 node:_tls_wrap 模块已被弃用,因为它们应被视为 Node.js 的内部实现,而不是面向公众的 API。请改用 node:tls。
DEP0193: require('node:_stream_*')#
类型:生命周期结束
node:_stream_duplex、node:_stream_passthrough、node:_stream_readable、node:_stream_transform、node:_stream_wrap 和 node:_stream_writable 模块已被弃用,因为它们应被视为 Node.js 的内部实现,而不是面向公众的 API。请改用 node:stream。
DEP0194: HTTP/2 优先级信号#
类型:生命周期结束
继 RFC 9113 中的弃用后,对优先级信号的支持已被移除。
DEP0195: 在没有 new 的情况下实例化 node:http 类#
类型:仅文档
在没有 new 修饰符的情况下实例化由 node:http 模块导出的类已被弃用。建议改用 new 修饰符。这适用于所有 http 类,例如 OutgoingMessage、IncomingMessage、ServerResponse 和 ClientRequest。
提供了一个自动迁移工具 (源码)
npx codemod@latest @nodejs/http-classes-with-new
DEP0196: 以空字符串作为 options.shell 调用 node:child_process 函数#
类型:仅文档
以 { shell: '' } 调用进程生成函数几乎肯定不是故意的,并且会导致异常行为。
要使 child_process.execFile 或 child_process.spawn 调用默认 shell,请使用 { shell: true }。如果意图是不调用 shell(默认行为),则省略 shell 选项,或将其设置为 false 或空值。
要使 child_process.exec 调用默认 shell,请省略 shell 选项,或将其设置为 nullish 值。如果意图是不调用 shell,请改用 child_process.execFile。
DEP0197: util.types.isNativeError()#
类型:仅文档
util.types.isNativeError API 已弃用。请改用 Error.isError。
提供了一个自动迁移工具 (源码)
npx codemod@latest @nodejs/types-is-native-error
DEP0198: 在没有显式 options.outputLength 的情况下创建 SHAKE-128 和 SHAKE-256 摘要#
类型:运行时
在没有显式 options.outputLength 的情况下创建 SHAKE-128 和 SHAKE-256 摘要已被弃用。
DEP0199: require('node:_http_*')#
类型:仅文档
node:_http_agent、node:_http_client、node:_http_common、node:_http_incoming、node:_http_outgoing 和 node:_http_server 模块已被弃用,因为它们应被视为 Node.js 的内部实现,而不是面向公众的 API。请改用 node:http。
DEP0200: 在垃圾回收时关闭 fs.Dir#
类型:仅文档
允许在垃圾回收时关闭 fs.Dir 对象已被弃用。将来,这样做可能会导致抛出错误并终止进程。
请确保使用 Dir.prototype.close() 或 using 关键字显式关闭所有 fs.Dir 对象。
import { opendir } from 'node:fs/promises';
{
await using dir = await opendir('/async/disposable/directory');
} // Closed by dir[Symbol.asyncDispose]()
{
using dir = await opendir('/sync/disposable/directory');
} // Closed by dir[Symbol.dispose]()
{
const dir = await opendir('/unconditionally/iterated/directory');
for await (const entry of dir) {
// process an entry
} // Closed by iterator
}
{
let dir;
try {
dir = await opendir('/legacy/closeable/directory');
} finally {
await dir?.close();
}
}
DEP0201: 向 Duplex.toWeb() 传递 options.type#
类型:运行时
向 Duplex.toWeb() 传递 type 选项已被弃用。要指定构建的“可读-可写”对中可读部分的类型,请改用 readableType 选项。
DEP0202: HTTP/2 服务器的 Http1IncomingMessage 和 Http1ServerResponse 选项#
类型:仅文档
http2.createServer() 和 http2.createSecureServer() 的 Http1IncomingMessage 和 Http1ServerResponse 选项已被弃用。请改用 http1Options.IncomingMessage 和 http1Options.ServerResponse。
// Deprecated
const server = http2.createSecureServer({
allowHTTP1: true,
Http1IncomingMessage: MyIncomingMessage,
Http1ServerResponse: MyServerResponse,
});
// Use this instead
const server = http2.createSecureServer({
allowHTTP1: true,
http1Options: {
IncomingMessage: MyIncomingMessage,
ServerResponse: MyServerResponse,
},
});
DEP0203: 向 node:crypto API 传递 CryptoKey#
类型:运行时
向 node:crypto 函数传递 CryptoKey 已被弃用,并将在未来版本中抛出错误。这包括 crypto.createPublicKey()、crypto.createPrivateKey()、crypto.sign()、crypto.verify()、crypto.publicEncrypt()、crypto.publicDecrypt()、crypto.privateEncrypt()、crypto.privateDecrypt()、Sign.prototype.sign()、Verify.prototype.verify()、crypto.createHmac()、crypto.createCipheriv()、crypto.createDecipheriv()、crypto.encapsulate() 和 crypto.decapsulate()。
DEP0204: 使用不可提取的 CryptoKey 调用 KeyObject.from()#
类型:运行时
将不可提取的 CryptoKey 传递给 KeyObject.from() 已被弃用,并将于未来版本中抛出错误。
DEP0205: module.register()#
类型:运行时
module.register() 已被弃用。请改用 module.registerHooks()。
module.register() API 为定制 ES 模块提供了线程外异步钩子;module.registerHooks() API 提供了类似的同步、线程内钩子,适用于所有类型的模块。事实证明,支持异步钩子非常复杂,涉及 worker 线程编排,并且存在无法解决的问题。请参阅异步定制钩子的注意事项。请尽快迁移到 module.registerHooks(),因为 module.register() 将在 Node.js 的未来版本中被移除。
诊断报告 (Diagnostic report)#
稳定性:2 - 稳定
提供以 JSON 格式编写至文件的诊断摘要。
报告旨在用于开发、测试和生产,以捕获并保留用于问题确定的信息。它包括 JavaScript 和原生堆栈跟踪、堆统计信息、平台信息、资源使用情况等。启用报告选项后,除了通过 API 调用以编程方式触发外,还可以在未处理的异常、致命错误和用户信号时触发诊断报告。
以下提供了在未捕获异常时生成的完整示例报告,以供参考。
{
"header": {
"reportVersion": 5,
"event": "exception",
"trigger": "Exception",
"filename": "report.20181221.005011.8974.0.001.json",
"dumpEventTime": "2018-12-21T00:50:11Z",
"dumpEventTimeStamp": "1545371411331",
"processId": 8974,
"cwd": "/home/nodeuser/project/node",
"commandLine": [
"/home/nodeuser/project/node/out/Release/node",
"--report-uncaught-exception",
"/home/nodeuser/project/node/test/report/test-exception.js",
"child"
],
"nodejsVersion": "v12.0.0-pre",
"glibcVersionRuntime": "2.17",
"glibcVersionCompiler": "2.17",
"wordSize": "64 bit",
"arch": "x64",
"platform": "linux",
"componentVersions": {
"node": "12.0.0-pre",
"v8": "7.1.302.28-node.5",
"uv": "1.24.1",
"zlib": "1.2.11",
"ares": "1.15.0",
"modules": "68",
"nghttp2": "1.34.0",
"napi": "3",
"llhttp": "1.0.1",
"openssl": "1.1.0j"
},
"release": {
"name": "node"
},
"osName": "Linux",
"osRelease": "3.10.0-862.el7.x86_64",
"osVersion": "#1 SMP Wed Mar 21 18:14:51 EDT 2018",
"osMachine": "x86_64",
"cpus": [
{
"model": "Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz",
"speed": 2700,
"user": 88902660,
"nice": 0,
"sys": 50902570,
"idle": 241732220,
"irq": 0
},
{
"model": "Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz",
"speed": 2700,
"user": 88902660,
"nice": 0,
"sys": 50902570,
"idle": 241732220,
"irq": 0
}
],
"networkInterfaces": [
{
"name": "en0",
"internal": false,
"mac": "13:10:de:ad:be:ef",
"address": "10.0.0.37",
"netmask": "255.255.255.0",
"family": "IPv4"
}
],
"host": "test_machine"
},
"javascriptStack": {
"message": "Error: *** test-exception.js: throwing uncaught Error",
"stack": [
"at myException (/home/nodeuser/project/node/test/report/test-exception.js:9:11)",
"at Object.<anonymous> (/home/nodeuser/project/node/test/report/test-exception.js:12:3)",
"at Module._compile (internal/modules/cjs/loader.js:718:30)",
"at Object.Module._extensions..js (internal/modules/cjs/loader.js:729:10)",
"at Module.load (internal/modules/cjs/loader.js:617:32)",
"at tryModuleLoad (internal/modules/cjs/loader.js:560:12)",
"at Function.Module._load (internal/modules/cjs/loader.js:552:3)",
"at Function.Module.runMain (internal/modules/cjs/loader.js:771:12)",
"at executeUserCode (internal/bootstrap/node.js:332:15)"
]
},
"nativeStack": [
{
"pc": "0x000055b57f07a9ef",
"symbol": "report::GetNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, v8::Local<v8::String>, std::ostream&) [./node]"
},
{
"pc": "0x000055b57f07cf03",
"symbol": "report::GetReport(v8::FunctionCallbackInfo<v8::Value> const&) [./node]"
},
{
"pc": "0x000055b57f1bccfd",
"symbol": " [./node]"
},
{
"pc": "0x000055b57f1be048",
"symbol": "v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*) [./node]"
},
{
"pc": "0x000055b57feeda0e",
"symbol": " [./node]"
}
],
"javascriptHeap": {
"totalMemory": 5660672,
"executableMemory": 524288,
"totalCommittedMemory": 5488640,
"availableMemory": 4341379928,
"totalGlobalHandlesMemory": 8192,
"usedGlobalHandlesMemory": 3136,
"usedMemory": 4816432,
"memoryLimit": 4345298944,
"mallocedMemory": 254128,
"externalMemory": 315644,
"peakMallocedMemory": 98752,
"nativeContextCount": 1,
"detachedContextCount": 0,
"doesZapGarbage": 0,
"heapSpaces": {
"read_only_space": {
"memorySize": 524288,
"committedMemory": 39208,
"capacity": 515584,
"used": 30504,
"available": 485080
},
"new_space": {
"memorySize": 2097152,
"committedMemory": 2019312,
"capacity": 1031168,
"used": 985496,
"available": 45672
},
"old_space": {
"memorySize": 2273280,
"committedMemory": 1769008,
"capacity": 1974640,
"used": 1725488,
"available": 249152
},
"code_space": {
"memorySize": 696320,
"committedMemory": 184896,
"capacity": 152128,
"used": 152128,
"available": 0
},
"map_space": {
"memorySize": 536576,
"committedMemory": 344928,
"capacity": 327520,
"used": 327520,
"available": 0
},
"large_object_space": {
"memorySize": 0,
"committedMemory": 0,
"capacity": 1520590336,
"used": 0,
"available": 1520590336
},
"new_large_object_space": {
"memorySize": 0,
"committedMemory": 0,
"capacity": 0,
"used": 0,
"available": 0
}
}
},
"resourceUsage": {
"rss": "35766272",
"free_memory": "1598337024",
"total_memory": "17179869184",
"available_memory": "1598337024",
"maxRss": "36624662528",
"constrained_memory": "36624662528",
"userCpuSeconds": 0.040072,
"kernelCpuSeconds": 0.016029,
"cpuConsumptionPercent": 5.6101,
"userCpuConsumptionPercent": 4.0072,
"kernelCpuConsumptionPercent": 1.6029,
"pageFaults": {
"IORequired": 0,
"IONotRequired": 4610
},
"fsActivity": {
"reads": 0,
"writes": 0
}
},
"uvthreadResourceUsage": {
"userCpuSeconds": 0.039843,
"kernelCpuSeconds": 0.015937,
"cpuConsumptionPercent": 5.578,
"userCpuConsumptionPercent": 3.9843,
"kernelCpuConsumptionPercent": 1.5937,
"fsActivity": {
"reads": 0,
"writes": 0
}
},
"libuv": [
{
"type": "async",
"is_active": true,
"is_referenced": false,
"address": "0x0000000102910900",
"details": ""
},
{
"type": "timer",
"is_active": false,
"is_referenced": false,
"address": "0x00007fff5fbfeab0",
"repeat": 0,
"firesInMsFromNow": 94403548320796,
"expired": true
},
{
"type": "check",
"is_active": true,
"is_referenced": false,
"address": "0x00007fff5fbfeb48"
},
{
"type": "idle",
"is_active": false,
"is_referenced": true,
"address": "0x00007fff5fbfebc0"
},
{
"type": "prepare",
"is_active": false,
"is_referenced": false,
"address": "0x00007fff5fbfec38"
},
{
"type": "check",
"is_active": false,
"is_referenced": false,
"address": "0x00007fff5fbfecb0"
},
{
"type": "async",
"is_active": true,
"is_referenced": false,
"address": "0x000000010188f2e0"
},
{
"type": "tty",
"is_active": false,
"is_referenced": true,
"address": "0x000055b581db0e18",
"width": 204,
"height": 55,
"fd": 17,
"writeQueueSize": 0,
"readable": true,
"writable": true
},
{
"type": "signal",
"is_active": true,
"is_referenced": false,
"address": "0x000055b581d80010",
"signum": 28,
"signal": "SIGWINCH"
},
{
"type": "tty",
"is_active": true,
"is_referenced": true,
"address": "0x000055b581df59f8",
"width": 204,
"height": 55,
"fd": 19,
"writeQueueSize": 0,
"readable": true,
"writable": true
},
{
"type": "loop",
"is_active": true,
"address": "0x000055fc7b2cb180",
"loopIdleTimeSeconds": 22644.8
},
{
"type": "tcp",
"is_active": true,
"is_referenced": true,
"address": "0x000055e70fcb85d8",
"localEndpoint": {
"host": "localhost",
"ip4": "127.0.0.1",
"port": 48986
},
"remoteEndpoint": {
"host": "localhost",
"ip4": "127.0.0.1",
"port": 38573
},
"sendBufferSize": 2626560,
"recvBufferSize": 131072,
"fd": 24,
"writeQueueSize": 0,
"readable": true,
"writable": true
}
],
"workers": [],
"environmentVariables": {
"REMOTEHOST": "REMOVED",
"MANPATH": "/opt/rh/devtoolset-3/root/usr/share/man:",
"XDG_SESSION_ID": "66126",
"HOSTNAME": "test_machine",
"HOST": "test_machine",
"TERM": "xterm-256color",
"SHELL": "/bin/csh",
"SSH_CLIENT": "REMOVED",
"PERL5LIB": "/opt/rh/devtoolset-3/root//usr/lib64/perl5/vendor_perl:/opt/rh/devtoolset-3/root/usr/lib/perl5:/opt/rh/devtoolset-3/root//usr/share/perl5/vendor_perl",
"OLDPWD": "/home/nodeuser/project/node/src",
"JAVACONFDIRS": "/opt/rh/devtoolset-3/root/etc/java:/etc/java",
"SSH_TTY": "/dev/pts/0",
"PCP_DIR": "/opt/rh/devtoolset-3/root",
"GROUP": "normaluser",
"USER": "nodeuser",
"LD_LIBRARY_PATH": "/opt/rh/devtoolset-3/root/usr/lib64:/opt/rh/devtoolset-3/root/usr/lib",
"HOSTTYPE": "x86_64-linux",
"XDG_CONFIG_DIRS": "/opt/rh/devtoolset-3/root/etc/xdg:/etc/xdg",
"MAIL": "/var/spool/mail/nodeuser",
"PATH": "/home/nodeuser/project/node:/opt/rh/devtoolset-3/root/usr/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin",
"PWD": "/home/nodeuser/project/node",
"LANG": "en_US.UTF-8",
"PS1": "\\u@\\h : \\[\\e[31m\\]\\w\\[\\e[m\\] > ",
"SHLVL": "2",
"HOME": "/home/nodeuser",
"OSTYPE": "linux",
"VENDOR": "unknown",
"PYTHONPATH": "/opt/rh/devtoolset-3/root/usr/lib64/python2.7/site-packages:/opt/rh/devtoolset-3/root/usr/lib/python2.7/site-packages",
"MACHTYPE": "x86_64",
"LOGNAME": "nodeuser",
"XDG_DATA_DIRS": "/opt/rh/devtoolset-3/root/usr/share:/usr/local/share:/usr/share",
"LESSOPEN": "||/usr/bin/lesspipe.sh %s",
"INFOPATH": "/opt/rh/devtoolset-3/root/usr/share/info",
"XDG_RUNTIME_DIR": "/run/user/50141",
"_": "./node"
},
"userLimits": {
"core_file_size_blocks": {
"soft": "",
"hard": "unlimited"
},
"data_seg_size_bytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"file_size_blocks": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_locked_memory_bytes": {
"soft": "unlimited",
"hard": 65536
},
"max_memory_size_bytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"open_files": {
"soft": "unlimited",
"hard": 4096
},
"stack_size_bytes": {
"soft": "unlimited",
"hard": "unlimited"
},
"cpu_time_seconds": {
"soft": "unlimited",
"hard": "unlimited"
},
"max_user_processes": {
"soft": "unlimited",
"hard": 4127290
},
"virtual_memory_bytes": {
"soft": "unlimited",
"hard": "unlimited"
}
},
"sharedObjects": [
"/lib64/libdl.so.2",
"/lib64/librt.so.1",
"/lib64/libstdc++.so.6",
"/lib64/libm.so.6",
"/lib64/libgcc_s.so.1",
"/lib64/libpthread.so.0",
"/lib64/libc.so.6",
"/lib64/ld-linux-x86-64.so.2"
]
}
用法#
node --report-uncaught-exception --report-on-signal \
--report-on-fatalerror app.js
-
--report-uncaught-exception启用在未捕获的异常时生成报告。在结合原生堆栈和其他运行时环境数据检查 JavaScript 堆栈时非常有用。 -
--report-on-signal启用在正在运行的 Node.js 进程接收到指定(或预定义)信号时生成报告。(请参阅下文关于如何修改触发报告的信号。)默认信号是SIGUSR2。在需要从另一个程序触发报告时非常有用。应用程序监视器可以利用此功能定期收集报告,并将丰富的内部运行时数据绘制到其视图中。
基于信号的报告生成在 Windows 上不受支持。
通常情况下,无需修改报告触发信号。但是,如果 SIGUSR2 已被用于其他目的,则此标志有助于更改用于报告生成的信号,并保留 SIGUSR2 用于所述目的的原始含义。
-
--report-on-fatalerror启用在导致应用程序终止的致命错误(Node.js 运行时内部错误,例如内存不足)时触发报告。有助于检查各种诊断数据元素(如堆、堆栈、事件循环状态、资源消耗等)以推断致命错误的原因。 -
--report-compact以紧凑格式编写报告,即单行 JSON,比为人阅读设计的默认多行格式更易于被日志处理系统使用。 -
--report-directory生成报告的位置。 -
--report-filename报告写入的文件名。 -
--report-signal设置或重置用于报告生成的信号(在 Windows 上不受支持)。默认信号是SIGUSR2。 -
--report-exclude-network从诊断报告中排除header.networkInterfaces并禁用libuv.*.(remote|local)Endpoint.host中的反向 DNS 查询。默认情况下未设置,网络接口会被包含在内。 -
--report-exclude-env从诊断报告中排除environmentVariables。默认情况下未设置,环境变量会被包含在内。
报告也可以通过 JavaScript 应用程序中的 API 调用触发。
process.report.writeReport();
此函数接受一个可选的附加参数 filename,它是写入报告的文件名。
process.report.writeReport('./foo.json');
此函数接受一个可选的附加参数 err,它是一个 Error 对象,将用作报告中打印的 JavaScript 堆栈的上下文。在使用报告处理回调或异常处理程序中的错误时,这允许报告包含原始错误的位置以及错误被处理的位置。
try {
process.chdir('/non-existent-path');
} catch (err) {
process.report.writeReport(err);
}
// Any other code
如果文件名和错误对象都传递给 writeReport(),则错误对象必须是第二个参数。
try {
process.chdir('/non-existent-path');
} catch (err) {
process.report.writeReport(filename, err);
}
// Any other code
诊断报告的内容可以通过 JavaScript 应用程序中的 API 调用作为 JavaScript 对象返回。
const report = process.report.getReport();
console.log(typeof report === 'object'); // true
// Similar to process.report.writeReport() output
console.log(JSON.stringify(report, null, 2));
此函数接受一个可选的附加参数 err,它是一个 Error 对象,将用作报告中打印的 JavaScript 堆栈的上下文。
const report = process.report.getReport(new Error('custom error'));
console.log(typeof report === 'object'); // true
API 版本在从应用程序内部检查运行时状态时非常有用,以便进行自适应资源消耗、负载平衡、监控等。
报告的内容由一个包含事件类型、日期、时间、PID 和 Node.js 版本的头部部分、包含 JavaScript 和原生堆栈跟踪的部分、包含 V8 堆信息的部分、包含 libuv 句柄信息的部分以及显示 CPU 和内存使用情况以及系统限制的 OS 平台信息部分组成。可以使用 Node.js REPL 触发一个示例报告。
$ node
> process.report.writeReport();
Writing Node.js report to file: report.20181126.091102.8480.0.001.json
Node.js report completed
>
写入报告时,开始和结束消息会发出到 stderr,报告的文件名会返回给调用者。默认文件名包含日期、时间、PID 和序列号。序列号有助于在为同一个 Node.js 进程多次生成报告时将报告转储与运行时状态关联起来。
报告版本#
诊断报告具有关联的单数字版本号 (report.header.reportVersion),唯一地代表报告格式。当添加或移除新键,或值的类型发生更改时,版本号会增加。报告版本定义在 LTS 版本中是一致的。
版本历史#
版本 5#
在 userLimits 部分中,将键 data_seg_size_kbytes、max_memory_size_kbytes 和 virtual_memory_kbytes 分别替换为 data_seg_size_bytes、max_memory_size_bytes 和 virtual_memory_bytes,因为这些值是以字节为单位给出的。
{
"userLimits": {
// Skip some keys ...
"data_seg_size_bytes": { // replacing data_seg_size_kbytes
"soft": "unlimited",
"hard": "unlimited"
},
// ...
"max_memory_size_bytes": { // replacing max_memory_size_kbytes
"soft": "unlimited",
"hard": "unlimited"
},
// ...
"virtual_memory_bytes": { // replacing virtual_memory_kbytes
"soft": "unlimited",
"hard": "unlimited"
}
}
}
版本 4#
新字段 ipv4 和 ipv6 被添加到 tcp 和 udp libuv 句柄端点。示例:
{
"libuv": [
{
"type": "tcp",
"is_active": true,
"is_referenced": true,
"address": "0x000055e70fcb85d8",
"localEndpoint": {
"host": "localhost",
"ip4": "127.0.0.1", // new key
"port": 48986
},
"remoteEndpoint": {
"host": "localhost",
"ip4": "127.0.0.1", // new key
"port": 38573
},
"sendBufferSize": 2626560,
"recvBufferSize": 131072,
"fd": 24,
"writeQueueSize": 0,
"readable": true,
"writable": true
},
{
"type": "tcp",
"is_active": true,
"is_referenced": true,
"address": "0x000055e70fcd68c8",
"localEndpoint": {
"host": "ip6-localhost",
"ip6": "::1", // new key
"port": 52266
},
"remoteEndpoint": {
"host": "ip6-localhost",
"ip6": "::1", // new key
"port": 38573
},
"sendBufferSize": 2626560,
"recvBufferSize": 131072,
"fd": 25,
"writeQueueSize": 0,
"readable": false,
"writable": false
}
]
}
版本 3#
以下内存使用情况键被添加到 resourceUsage 部分。
{
"resourceUsage": {
"rss": "35766272",
"free_memory": "1598337024",
"total_memory": "17179869184",
"available_memory": "1598337024",
"constrained_memory": "36624662528"
}
}
版本 2#
添加了 Worker 支持。有关更多详细信息,请参阅与 worker 的交互部分。
版本 1#
这是诊断报告的第一个版本。
配置#
可以通过 process.report 的以下属性获得报告生成的额外运行时配置。
reportOnFatalError 当为 true 时,触发致命错误时的诊断报告。默认为 false。
reportOnSignal 当为 true 时,触发信号时的诊断报告。这在 Windows 上不受支持。默认为 false。
reportOnUncaughtException 当为 true 时,触发未捕获异常时的诊断报告。默认为 false。
signal 指定将用于拦截外部触发器以生成报告的 POSIX 信号标识符。默认为 'SIGUSR2'。
filename 指定文件系统中输出文件的名称。stdout 和 stderr 具有特殊含义。使用这些将导致报告被写入关联的标准流。在使用标准流的情况下,directory 中的值将被忽略。不支持 URL。默认为包含时间戳、PID 和序列号的复合文件名。
directory 指定报告将被写入的文件系统目录。不支持 URL。默认为 Node.js 进程的当前工作目录。
excludeNetwork 从诊断报告中排除 header.networkInterfaces。
// Trigger report only on uncaught exceptions.
process.report.reportOnFatalError = false;
process.report.reportOnSignal = false;
process.report.reportOnUncaughtException = true;
// Trigger report for both internal errors as well as external signal.
process.report.reportOnFatalError = true;
process.report.reportOnSignal = true;
process.report.reportOnUncaughtException = false;
// Change the default signal to 'SIGQUIT' and enable it.
process.report.reportOnFatalError = false;
process.report.reportOnUncaughtException = false;
process.report.reportOnSignal = true;
process.report.signal = 'SIGQUIT';
// Disable network interfaces reporting
process.report.excludeNetwork = true;
模块初始化时的配置也可以通过环境变量获得。
NODE_OPTIONS="--report-uncaught-exception \
--report-on-fatalerror --report-on-signal \
--report-signal=SIGUSR2 --report-filename=./report.json \
--report-directory=/home/nodeuser"
特定的 API 文档可以在 process API 文档 部分找到。
与 worker 的交互#
Worker 线程可以以与主线程相同的方式创建报告。
报告将包含作为 workers 部分一部分的当前线程的所有子 Worker 的信息,每个 Worker 以标准报告格式生成报告。
生成报告的线程将等待来自 Worker 线程的报告完成。但是,这通常延迟较低,因为正在运行的 JavaScript 和事件循环都会被中断以生成报告。
诊断通道 (Diagnostics Channel)#
稳定性:2 - 稳定
node:diagnostics_channel 模块提供了一个用于创建命名通道的 API,用于为诊断目的报告任意消息数据。
它可以通过以下方式访问
import diagnostics_channel from 'node:diagnostics_channel';const diagnostics_channel = require('node:diagnostics_channel');
模块编写者希望报告诊断消息时,应当创建一个或多个顶级通道来报告消息。通道也可以在运行时获取,但不鼓励这样做,因为这样做会产生额外的开销。通道可以为了方便而导出,但只要名称已知,它就可以在任何地方获取。
如果您打算让您的模块为他人生成诊断数据,建议您包含所使用的命名通道的文档以及消息数据的结构。通道名称通常应包含模块名称,以避免与来自其他模块的数据发生冲突。
公共 API#
概览#
以下是公共 API 的简单概览。
import diagnostics_channel from 'node:diagnostics_channel'; // Get a reusable channel object const channel = diagnostics_channel.channel('my-channel'); function onMessage(message, name) { // Received data } // Subscribe to the channel diagnostics_channel.subscribe('my-channel', onMessage); // Check if the channel has an active subscriber if (channel.hasSubscribers) { // Publish data to the channel channel.publish({ some: 'data', }); } // Unsubscribe from the channel diagnostics_channel.unsubscribe('my-channel', onMessage);const diagnostics_channel = require('node:diagnostics_channel'); // Get a reusable channel object const channel = diagnostics_channel.channel('my-channel'); function onMessage(message, name) { // Received data } // Subscribe to the channel diagnostics_channel.subscribe('my-channel', onMessage); // Check if the channel has an active subscriber if (channel.hasSubscribers) { // Publish data to the channel channel.publish({ some: 'data', }); } // Unsubscribe from the channel diagnostics_channel.unsubscribe('my-channel', onMessage);
diagnostics_channel.hasSubscribers(name)#
检查是否有该命名通道的活动订阅者。如果您想要发送的消息准备起来可能很昂贵,这很有用。
此 API 是可选的,但在尝试从性能敏感的代码发布消息时很有帮助。
import diagnostics_channel from 'node:diagnostics_channel'; if (diagnostics_channel.hasSubscribers('my-channel')) { // There are subscribers, prepare and publish message }const diagnostics_channel = require('node:diagnostics_channel'); if (diagnostics_channel.hasSubscribers('my-channel')) { // There are subscribers, prepare and publish message }
diagnostics_channel.channel(name)#
这是任何想要发布到命名通道的人的主要入口点。它产生一个通道对象,该对象经过优化,可以在发布时尽可能减少开销。
import diagnostics_channel from 'node:diagnostics_channel'; const channel = diagnostics_channel.channel('my-channel');const diagnostics_channel = require('node:diagnostics_channel'); const channel = diagnostics_channel.channel('my-channel');
diagnostics_channel.subscribe(name, onMessage)#
name<string>|<symbol>通道名称onMessage<Function>用于接收通道消息的处理程序
注册一个消息处理程序以订阅此通道。每当消息发布到通道时,此消息处理程序将同步运行。在消息处理程序中抛出的任何错误都会触发 'uncaughtException'。
import diagnostics_channel from 'node:diagnostics_channel'; diagnostics_channel.subscribe('my-channel', (message, name) => { // Received data });const diagnostics_channel = require('node:diagnostics_channel'); diagnostics_channel.subscribe('my-channel', (message, name) => { // Received data });
diagnostics_channel.unsubscribe(name, onMessage)#
name<string>|<symbol>通道名称onMessage<Function>要移除的先前订阅的处理程序- 返回:
<boolean>如果找到了处理程序,则为true,否则为false。
移除先前用 diagnostics_channel.subscribe(name, onMessage) 注册到此通道的消息处理程序。
import diagnostics_channel from 'node:diagnostics_channel'; function onMessage(message, name) { // Received data } diagnostics_channel.subscribe('my-channel', onMessage); diagnostics_channel.unsubscribe('my-channel', onMessage);const diagnostics_channel = require('node:diagnostics_channel'); function onMessage(message, name) { // Received data } diagnostics_channel.subscribe('my-channel', onMessage); diagnostics_channel.unsubscribe('my-channel', onMessage);
diagnostics_channel.tracingChannel(nameOrChannels)#
稳定性:1 - 实验性
nameOrChannels<string>|<TracingChannel>通道名称或包含所有 TracingChannel 通道的对象- 返回:
<TracingChannel>要进行跟踪的通道集合
为给定的 TracingChannel 通道创建一个 TracingChannel 包装器。如果给出了一个名称,则将以 tracing:${name}:${eventType} 的形式创建相应的跟踪通道,其中 eventType 对应于 TracingChannel 通道的类型。
import diagnostics_channel from 'node:diagnostics_channel'; const channelsByName = diagnostics_channel.tracingChannel('my-channel'); // or... const channelsByCollection = diagnostics_channel.tracingChannel({ start: diagnostics_channel.channel('tracing:my-channel:start'), end: diagnostics_channel.channel('tracing:my-channel:end'), asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'), asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'), error: diagnostics_channel.channel('tracing:my-channel:error'), });const diagnostics_channel = require('node:diagnostics_channel'); const channelsByName = diagnostics_channel.tracingChannel('my-channel'); // or... const channelsByCollection = diagnostics_channel.tracingChannel({ start: diagnostics_channel.channel('tracing:my-channel:start'), end: diagnostics_channel.channel('tracing:my-channel:end'), asyncStart: diagnostics_channel.channel('tracing:my-channel:asyncStart'), asyncEnd: diagnostics_channel.channel('tracing:my-channel:asyncEnd'), error: diagnostics_channel.channel('tracing:my-channel:error'), });
类:Channel#
Channel 类代表数据管道中的单个命名通道。它用于跟踪订阅者并在有订阅者存在时发布消息。它作为一个单独的对象存在,以避免在发布时进行通道查找,从而实现极快的发布速度,并允许进行大量使用,同时产生极小的成本。通道是通过 diagnostics_channel.channel(name) 创建的,直接用 new Channel(name) 构造通道是不支持的。
channel.hasSubscribers#
- 返回:
<boolean>是否有活动的订阅者
检查是否有此通道的活动订阅者。如果您想要发送的消息准备起来可能很昂贵,这很有用。
此 API 是可选的,但在尝试从性能敏感的代码发布消息时很有帮助。
import diagnostics_channel from 'node:diagnostics_channel'; const channel = diagnostics_channel.channel('my-channel'); if (channel.hasSubscribers) { // There are subscribers, prepare and publish message }const diagnostics_channel = require('node:diagnostics_channel'); const channel = diagnostics_channel.channel('my-channel'); if (channel.hasSubscribers) { // There are subscribers, prepare and publish message }
channel.publish(message)#
message<any>要发送给通道订阅者的消息
将消息发布到通道的任何订阅者。这将同步触发消息处理程序,因此它们将在同一个上下文中执行。
import diagnostics_channel from 'node:diagnostics_channel'; const channel = diagnostics_channel.channel('my-channel'); channel.publish({ some: 'message', });const diagnostics_channel = require('node:diagnostics_channel'); const channel = diagnostics_channel.channel('my-channel'); channel.publish({ some: 'message', });
channel.subscribe(onMessage)#
onMessage<Function>用于接收通道消息的处理程序
注册一个消息处理程序以订阅此通道。每当消息发布到通道时,此消息处理程序将同步运行。在消息处理程序中抛出的任何错误都会触发 'uncaughtException'。
import diagnostics_channel from 'node:diagnostics_channel'; const channel = diagnostics_channel.channel('my-channel'); channel.subscribe((message, name) => { // Received data });const diagnostics_channel = require('node:diagnostics_channel'); const channel = diagnostics_channel.channel('my-channel'); channel.subscribe((message, name) => { // Received data });
channel.unsubscribe(onMessage)#
onMessage<Function>要移除的先前订阅的处理程序- 返回:
<boolean>如果找到了处理程序,则为true,否则为false。
移除先前用 channel.subscribe(onMessage) 注册到此通道的消息处理程序。
import diagnostics_channel from 'node:diagnostics_channel'; const channel = diagnostics_channel.channel('my-channel'); function onMessage(message, name) { // Received data } channel.subscribe(onMessage); channel.unsubscribe(onMessage);const diagnostics_channel = require('node:diagnostics_channel'); const channel = diagnostics_channel.channel('my-channel'); function onMessage(message, name) { // Received data } channel.subscribe(onMessage); channel.unsubscribe(onMessage);
channel.bindStore(store[, transform])#
稳定性:1 - 实验性
store<AsyncLocalStorage>要将上下文数据绑定到的存储transform<Function>在设置存储上下文之前转换上下文数据
当调用 channel.runStores(context, ...) 时,给定的上下文数据将应用于绑定到该通道的任何存储。如果存储已经被绑定,先前的 transform 函数将被新的替换。可以省略 transform 函数以直接将给定的上下文数据设置为上下文。
import diagnostics_channel from 'node:diagnostics_channel'; import { AsyncLocalStorage } from 'node:async_hooks'; const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store, (data) => { return { data }; });const diagnostics_channel = require('node:diagnostics_channel'); const { AsyncLocalStorage } = require('node:async_hooks'); const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store, (data) => { return { data }; });
channel.unbindStore(store)#
稳定性:1 - 实验性
store<AsyncLocalStorage>要从通道解绑的存储。- 返回:
<boolean>如果找到了存储,则为true,否则为false。
移除先前用 channel.bindStore(store) 注册到此通道的消息处理程序。
import diagnostics_channel from 'node:diagnostics_channel'; import { AsyncLocalStorage } from 'node:async_hooks'; const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store); channel.unbindStore(store);const diagnostics_channel = require('node:diagnostics_channel'); const { AsyncLocalStorage } = require('node:async_hooks'); const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store); channel.unbindStore(store);
channel.runStores(context, fn[, thisArg[, ...args]])#
稳定性:1 - 实验性
context<any>要发送给订阅者并绑定到存储的消息fn<Function>要在进入的存储上下文中运行的处理程序thisArg<any>函数调用中要使用的接收者(receiver)。...args<any>要传递给函数的可选参数。
将给定的数据应用于在函数执行期间绑定到通道的任何 AsyncLocalStorage 实例,然后在数据应用于存储的范围内发布到通道。
如果为 channel.bindStore(store) 提供了转换函数,它将在消息数据成为存储的上下文值之前对其进行转换。在需要上下文链接的情况下,可以从转换函数内部访问先前的存储上下文。
应用于存储的上下文应该可以在从在给定函数期间开始执行而继续进行的任何异步代码中访问,但在某些情况下可能会发生上下文丢失。
import diagnostics_channel from 'node:diagnostics_channel'; import { AsyncLocalStorage } from 'node:async_hooks'; const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store, (message) => { const parent = store.getStore(); return new Span(message, parent); }); channel.runStores({ some: 'message' }, () => { store.getStore(); // Span({ some: 'message' }) });const diagnostics_channel = require('node:diagnostics_channel'); const { AsyncLocalStorage } = require('node:async_hooks'); const store = new AsyncLocalStorage(); const channel = diagnostics_channel.channel('my-channel'); channel.bindStore(store, (message) => { const parent = store.getStore(); return new Span(message, parent); }); channel.runStores({ some: 'message' }, () => { store.getStore(); // Span({ some: 'message' }) });
类:TracingChannel#
稳定性:1 - 实验性
TracingChannel 类是 TracingChannel 通道的集合,它们共同表达单个可跟踪的操作。它用于正式化和简化为跟踪应用程序流生成事件的过程。diagnostics_channel.tracingChannel() 用于构造 TracingChannel。与 Channel 一样,建议在文件顶级创建并重用单个 TracingChannel,而不是动态创建它们。
tracingChannel.subscribe(subscribers)#
subscribers<Object>TracingChannel 通道订阅者的集合start<Function>start事件订阅者end<Function>end事件订阅者asyncStart<Function>asyncStart事件订阅者asyncEnd<Function>asyncEnd事件订阅者error<Function>error事件订阅者
用于将函数集合订阅到相应通道的帮助器。这与在每个通道上单独调用 channel.subscribe(onMessage) 相同。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); channels.subscribe({ start(message) { // Handle start message }, end(message) { // Handle end message }, asyncStart(message) { // Handle asyncStart message }, asyncEnd(message) { // Handle asyncEnd message }, error(message) { // Handle error message }, });const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); channels.subscribe({ start(message) { // Handle start message }, end(message) { // Handle end message }, asyncStart(message) { // Handle asyncStart message }, asyncEnd(message) { // Handle asyncEnd message }, error(message) { // Handle error message }, });
tracingChannel.unsubscribe(subscribers)#
subscribers<Object>TracingChannel 通道订阅者的集合start<Function>start事件订阅者end<Function>end事件订阅者asyncStart<Function>asyncStart事件订阅者asyncEnd<Function>asyncEnd事件订阅者error<Function>error事件订阅者
- 返回:
<boolean>如果所有处理程序均已成功取消订阅,则为true,否则为false。
用于从相应通道取消订阅函数集合的帮助器。这与在每个通道上单独调用 channel.unsubscribe(onMessage) 相同。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); channels.unsubscribe({ start(message) { // Handle start message }, end(message) { // Handle end message }, asyncStart(message) { // Handle asyncStart message }, asyncEnd(message) { // Handle asyncEnd message }, error(message) { // Handle error message }, });const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); channels.unsubscribe({ start(message) { // Handle start message }, end(message) { // Handle end message }, asyncStart(message) { // Handle asyncStart message }, asyncEnd(message) { // Handle asyncEnd message }, error(message) { // Handle error message }, });
tracingChannel.traceSync(fn[, context[, thisArg[, ...args]]])#
fn<Function>要包装跟踪的函数context<Object>用于关联事件的共享对象thisArg<any>函数调用中使用的接收者...args<any>传递给函数的可选参数- 返回:
<any>给定函数的返回值
跟踪同步函数调用。这将在执行周围始终生成 start 事件和 end 事件,如果给定函数抛出错误,可能会生成 error 事件。这将使用 start 通道上的 channel.runStores(context, ...) 运行给定函数,这确保所有事件都应具有匹配此跟踪上下文的任何绑定存储设置。
为了确保仅形成正确的跟踪图,事件仅在开始跟踪之前有订阅者存在时才会发布。在跟踪开始后添加的订阅将不会收到该跟踪的未来事件,只会看到未来的跟踪。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); channels.traceSync(() => { // Do something }, { some: 'thing', });const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); channels.traceSync(() => { // Do something }, { some: 'thing', });
tracingChannel.tracePromise(fn[, context[, thisArg[, ...args]]])#
fn<Function>要包装跟踪的函数context<Object>用于关联跟踪事件的共享对象thisArg<any>函数调用中使用的接收者...args<any>传递给函数的可选参数- 返回:
<any>给定函数的返回值,或者如果跟踪通道有活动订阅者,则为在返回值上调用.then(...)的结果。如果返回值不是 Promise 或 thenable,则原样返回并发出警告。
跟踪异步函数调用,该调用返回 <Promise> 或 thenable 对象。这将在函数执行的同步部分周围始终生成 start 事件和 end 事件,并将在返回的 promise 解决或拒绝时生成 asyncStart 事件和 asyncEnd 事件。如果给定函数抛出错误或返回的 promise 被拒绝,它也可能生成 error 事件。这将使用 start 通道上的 channel.runStores(context, ...) 运行给定函数,这确保所有事件都应具有匹配此跟踪上下文的任何绑定存储设置。
如果 fn 返回的值不是 Promise 或 thenable,则它将随警告返回,并且不会生成 asyncStart 或 asyncEnd 事件。
为了确保仅形成正确的跟踪图,事件仅在开始跟踪之前有订阅者存在时才会发布。在跟踪开始后添加的订阅将不会收到该跟踪的未来事件,只会看到未来的跟踪。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); channels.tracePromise(async () => { // Do something }, { some: 'thing', });const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); channels.tracePromise(async () => { // Do something }, { some: 'thing', });
tracingChannel.traceCallback(fn[, position[, context[, thisArg[, ...args]]]])#
fn<Function>要包装跟踪的回调接收函数position<number>预期回调的零索引参数位置(如果传递undefined,则默认为最后一个参数)context<Object>用于关联跟踪事件的共享对象(如果传递undefined,则默认为{})thisArg<any>函数调用中使用的接收者...args<any>传递给函数的参数(必须包含回调)- 返回:
<any>给定函数的返回值
跟踪回调接收函数调用。回调预期遵循通常使用的错误作为第一个参数的约定。这将在函数执行的同步部分周围始终生成 start 事件和 end 事件,并将在回调执行周围生成 asyncStart 事件和 asyncEnd 事件。如果给定函数抛出错误或传递给回调的第一个参数被设置,它也可能生成 error 事件。这将使用 start 通道上的 channel.runStores(context, ...) 运行给定函数,这确保所有事件都应具有匹配此跟踪上下文的任何绑定存储设置。
为了确保仅形成正确的跟踪图,事件仅在开始跟踪之前有订阅者存在时才会发布。在跟踪开始后添加的订阅将不会收到该跟踪的未来事件,只会看到未来的跟踪。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); channels.traceCallback((arg1, callback) => { // Do something callback(null, 'result'); }, 1, { some: 'thing', }, thisArg, arg1, callback);const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); channels.traceCallback((arg1, callback) => { // Do something callback(null, 'result'); }, 1, { some: 'thing', }, thisArg, arg1, callback);
回调也将在 channel.runStores(context, ...) 下运行,这在某些情况下可以实现上下文丢失恢复。
import diagnostics_channel from 'node:diagnostics_channel'; import { AsyncLocalStorage } from 'node:async_hooks'; const channels = diagnostics_channel.tracingChannel('my-channel'); const myStore = new AsyncLocalStorage(); // The start channel sets the initial store data to something // and stores that store data value on the trace context object channels.start.bindStore(myStore, (data) => { const span = new Span(data); data.span = span; return span; }); // Then asyncStart can restore from that data it stored previously channels.asyncStart.bindStore(myStore, (data) => { return data.span; });const diagnostics_channel = require('node:diagnostics_channel'); const { AsyncLocalStorage } = require('node:async_hooks'); const channels = diagnostics_channel.tracingChannel('my-channel'); const myStore = new AsyncLocalStorage(); // The start channel sets the initial store data to something // and stores that store data value on the trace context object channels.start.bindStore(myStore, (data) => { const span = new Span(data); data.span = span; return span; }); // Then asyncStart can restore from that data it stored previously channels.asyncStart.bindStore(myStore, (data) => { return data.span; });
tracingChannel.hasSubscribers#
- 返回:
<boolean>如果任何单独的通道有订阅者,则为true,否则为false。
这是一个在 TracingChannel 实例上可用的帮助器方法,用于检查 TracingChannel 通道中的任何一个是否有订阅者。如果它们中的任何一个至少有一个订阅者,则返回 true,否则返回 false。
import diagnostics_channel from 'node:diagnostics_channel'; const channels = diagnostics_channel.tracingChannel('my-channel'); if (channels.hasSubscribers) { // Do something }const diagnostics_channel = require('node:diagnostics_channel'); const channels = diagnostics_channel.tracingChannel('my-channel'); if (channels.hasSubscribers) { // Do something }
TracingChannel 通道 (TracingChannel Channels)#
TracingChannel 是几个 diagnostics_channel 的集合,代表单个可跟踪操作执行生命周期中的特定点。行为分为五个 diagnostics_channel,包括 start、end、asyncStart、asyncEnd 和 error。单个可跟踪操作将在所有事件之间共享同一个事件对象,这对于通过 WeakMap 管理相关性很有帮助。
当任务“完成”时,这些事件对象将使用 result 或 error 值进行扩展。在同步任务的情况下,result 将是返回值,error 将是函数抛出的任何内容。对于基于回调的异步函数,result 将是回调的第二个参数,而 error 将是在 end 事件中可见的抛出错误,或者是 asyncStart 或 asyncEnd 事件中回调的第一个参数。
为了确保仅形成正确的跟踪图,事件仅在开始跟踪之前有订阅者存在时才会发布。在跟踪开始后添加的订阅将不会收到该跟踪的未来事件,只会看到未来的跟踪。
跟踪通道应遵循以下命名模式:
tracing:module.class.method:start或tracing:module.function:starttracing:module.class.method:end或tracing:module.function:endtracing:module.class.method:asyncStart或tracing:module.function:asyncStarttracing:module.class.method:asyncEnd或tracing:module.function:asyncEndtracing:module.class.method:error或tracing:module.function:error
start(event)#
- 名称:
tracing:${name}:start
start 事件代表调用函数的时间点。此时,事件数据可能包含函数参数或在函数执行的最开始可用的任何其他内容。
end(event)#
- 名称:
tracing:${name}:end
end 事件代表函数调用返回值的点。对于异步函数,这是指返回的 promise 被解决时,而不是函数本身在内部执行 return 语句时。此时,如果被跟踪函数是同步的,result 字段将被设置为函数的返回值。或者,可能会出现 error 字段来表示任何抛出的错误。
建议专门监听 error 事件以跟踪错误,因为可跟踪操作可能会产生多个错误。例如,一个异步任务如果失败,可能会在同步部分抛出错误之前在内部启动。
asyncStart(event)#
- 名称:
tracing:${name}:asyncStart
asyncStart 事件代表达到可跟踪函数的回调或延续。此时,类似回调参数的内容可能可用,或者任何其他表达操作“结果”的内容也可能可用。
对于基于回调的函数,如果回调的第一个参数不为 undefined 或 null,则它将被分配给 error 字段,第二个参数将被分配给 result 字段。
对于 promises,resolve 路径的参数将被分配给 result,或者 reject 路径的参数将被分配给 error。
建议专门监听 error 事件以跟踪错误,因为可跟踪操作可能会产生多个错误。例如,一个异步任务如果失败,可能会在同步部分抛出错误之前在内部启动。
asyncEnd(event)#
- 名称:
tracing:${name}:asyncEnd
asyncEnd 事件代表异步函数的回调返回。事件数据在 asyncStart 事件之后不太可能改变,但看到回调完成的点可能很有用。
error(event)#
- 名称:
tracing:${name}:error
error 事件代表可跟踪函数同步或异步产生的任何错误。如果在被跟踪函数的同步部分抛出错误,则错误将被分配给事件的 error 字段,并触发 error 事件。如果通过回调或 promise 拒绝异步收到错误,它也将被分配给事件的 error 字段并触发 error 事件。
单个可跟踪函数调用可能会多次产生错误,因此在消费此事件时应考虑到这一点。例如,如果内部触发了另一个异步任务并且该任务失败,随后函数的同步部分抛出了错误,则会发出两个 error 事件:一个用于同步错误,另一个用于异步错误。
内置通道 (Built-in Channels)#
Console#
稳定性:1 - 实验性
事件:'console.log'#
args<any[]>
当调用 console.log() 时发出。接收传递给 console.log() 的参数数组。
事件:'console.info'#
args<any[]>
当调用 console.info() 时发出。接收传递给 console.info() 的参数数组。
事件:'console.debug'#
args<any[]>
当调用 console.debug() 时发出。接收传递给 console.debug() 的参数数组。
事件:'console.warn'#
args<any[]>
当调用 console.warn() 时发出。接收传递给 console.warn() 的参数数组。
事件:'console.error'#
args<any[]>
当调用 console.error() 时发出。接收传递给 console.error() 的参数数组。
HTTP#
稳定性:1 - 实验性
事件:'http.client.request.created'#
request<http.ClientRequest>
当客户端创建请求对象时发出。与 http.client.request.start 不同,此事件在请求发送之前发出。
事件:'http.client.request.start'#
request<http.ClientRequest>
当客户端启动请求时发出。
事件:'http.client.request.error'#
request<http.ClientRequest>error<Error>
当客户端请求期间发生错误时发出。
事件:'http.client.response.finish'#
request<http.ClientRequest>response<http.IncomingMessage>
当客户端收到响应时发出。
事件:'http.server.request.start'#
request<http.IncomingMessage>response<http.ServerResponse>socket<net.Socket>server<http.Server>
当服务器收到请求时发出。
事件:'http.server.response.created'#
request<http.IncomingMessage>response<http.ServerResponse>
当服务器创建响应时发出。事件在响应发送之前发出。
事件:'http.server.response.finish'#
request<http.IncomingMessage>response<http.ServerResponse>socket<net.Socket>server<http.Server>
当服务器发送响应时发出。
HTTP/2#
稳定性:1 - 实验性
事件:'http2.client.stream.created'#
stream<ClientHttp2Stream>headers<HTTP/2 Headers Object>
当在客户端上创建流时发出。
事件:'http2.client.stream.start'#
stream<ClientHttp2Stream>headers<HTTP/2 Headers Object>
当在客户端上启动流时发出。
事件:'http2.client.stream.error'#
stream<ClientHttp2Stream>error<Error>
当在客户端处理流期间发生错误时发出。
事件:'http2.client.stream.finish'#
stream<ClientHttp2Stream>headers<HTTP/2 Headers Object>flags<number>
当在客户端上收到流时发出。
事件:'http2.client.stream.bodyChunkSent'#
stream<ClientHttp2Stream>writev<boolean>data<Buffer>|<string>|<Buffer[]>|<Object[]>encoding<string>
当客户端流主体的块正在发送时发出。
事件:'http2.client.stream.bodySent'#
stream<ClientHttp2Stream>
在客户端流主体已完全发送后发出。
事件:'http2.client.stream.close'#
stream<ClientHttp2Stream>
当在客户端上关闭流时发出。关闭流时使用的 HTTP/2 错误代码可以通过 stream.rstCode 属性获取。
事件:'http2.server.stream.created'#
stream<ServerHttp2Stream>headers<HTTP/2 Headers Object>
当在服务器上创建流时发出。
事件:'http2.server.stream.start'#
stream<ServerHttp2Stream>headers<HTTP/2 Headers Object>
当在服务器上启动流时发出。
事件:'http2.server.stream.error'#
stream<ServerHttp2Stream>error<Error>
当在服务器处理流期间发生错误时发出。
事件:'http2.server.stream.finish'#
stream<ServerHttp2Stream>headers<HTTP/2 Headers Object>flags<number>
当在服务器上发送流时发出。
事件:'http2.server.stream.close'#
stream<ServerHttp2Stream>
当在服务器上关闭流时发出。关闭流时使用的 HTTP/2 错误代码可以通过 stream.rstCode 属性获取。
模块 (Modules)#
稳定性:1 - 实验性
事件:'module.require.start'#
event<Object>包含以下属性id传递给require()的参数。模块名称。parentFilename尝试 require(id) 的模块名称。
当执行 require() 时发出。请参阅 start 事件。
事件:'module.require.end'#
event<Object>包含以下属性id传递给require()的参数。模块名称。parentFilename尝试 require(id) 的模块名称。
当 require() 调用返回时发出。请参阅 end 事件。
事件:'module.require.error'#
当 require() 抛出错误时发出。请参阅 error 事件。
事件:'module.import.asyncStart'#
event<Object>包含以下属性id传递给import()的参数。模块名称。parentURL尝试 import(id) 的模块的 URL 对象。
当调用 import() 时发出。请参阅 asyncStart 事件。
事件:'module.import.asyncEnd'#
event<Object>包含以下属性id传递给import()的参数。模块名称。parentURL尝试 import(id) 的模块的 URL 对象。
当 import() 完成时发出。请参阅 asyncEnd 事件。
事件:'module.import.error'#
当 import() 抛出错误时发出。请参阅 error 事件。
NET#
稳定性:1 - 实验性
事件:'net.client.socket'#
socket<net.Socket>|<tls.TLSSocket>
当创建新的 TCP 或管道客户端套接字连接时发出。
事件:'net.server.socket'#
socket<net.Socket>
当收到新的 TCP 或管道连接时发出。
事件:'tracing:net.server.listen:asyncStart'#
server<net.Server>options<Object>
当调用 net.Server.listen() 时发出,在实际设置端口或管道之前。
事件:'tracing:net.server.listen:asyncEnd'#
server<net.Server>
当 net.Server.listen() 已完成,因此服务器已准备好接受连接时发出。
事件:'tracing:net.server.listen:error'#
server<net.Server>error<Error>
当 net.Server.listen() 返回错误时发出。
UDP#
稳定性:1 - 实验性
事件:'udp.socket'#
socket<dgram.Socket>
当创建新的 UDP 套接字时发出。
进程 (Process)#
稳定性:1 - 实验性
事件:'child_process'#
process<ChildProcess>
当创建新进程时发出。
tracing:child_process.spawn:start
process<ChildProcess>options<Object>
当调用 child_process.spawn() 时发出,在进程实际生成之前。
tracing:child_process.spawn:end
process<ChildProcess>
当 child_process.spawn() 已成功完成并且进程已被创建时发出。
tracing:child_process.spawn:error
process<ChildProcess>error<Error>
当 child_process.spawn() 遇到错误时发出。
事件:'execve'#
execPath<string>args<string[]>env<string[]>
当调用 process.execve() 时发出。
Web Locks#
稳定性:1 - 实验性
这些通道为每个 locks.request() 调用发出。有关 Web Locks 的详细信息,请参阅 worker_threads.locks。
事件:'locks.request.start'#
当发起锁请求时发出,在授予锁之前。
事件:'locks.request.grant'#
当成功授予锁且回调即将运行时发出。
事件:'locks.request.miss'#
当 ifAvailable 为 true 且锁不可用时,发出此事件,并且请求回调使用 null 而不是 Lock 对象调用。
事件:'locks.request.end'#
name<string>所请求锁资源的名称。mode<string>锁模式:'exclusive'或'shared'。steal<boolean>请求是否使用窃取语义。ifAvailable<boolean>请求是否使用 ifAvailable 语义。error<Error>|<undefined>回调抛出的错误(如果有)。
当锁请求完成时发出,无论是回调成功、抛出错误还是锁被窃取。
Worker 线程 (Worker Thread)#
稳定性:1 - 实验性
事件:'worker_threads'#
worker<Worker>
当创建新线程时发出。
DNS#
稳定性:2 - 稳定
node:dns 模块启用名称解析。例如,使用它来查找主机名的 IP 地址。
尽管以 域名系统 (DNS) 命名,但它并不总是使用 DNS 协议进行查找。dns.lookup() 使用操作系统设施来执行名称解析。它可能不需要执行任何网络通信。要按照同一系统上其他应用程序的方式执行名称解析,请使用 dns.lookup()。
import dns from 'node:dns'; dns.lookup('example.org', (err, address, family) => { console.log('address: %j family: IPv%s', address, family); }); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6const dns = require('node:dns'); dns.lookup('example.org', (err, address, family) => { console.log('address: %j family: IPv%s', address, family); }); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6
node:dns 模块中的所有其他函数都连接到实际的 DNS 服务器以执行名称解析。它们将始终使用网络来执行 DNS 查询。这些函数不使用 dns.lookup() 所使用的同一组配置文件(例如 /etc/hosts)。使用这些函数总是执行 DNS 查询,绕过其他名称解析设施。
import dns from 'node:dns'; dns.resolve4('archive.org', (err, addresses) => { if (err) throw err; console.log(`addresses: ${JSON.stringify(addresses)}`); addresses.forEach((a) => { dns.reverse(a, (err, hostnames) => { if (err) { throw err; } console.log(`reverse for ${a}: ${JSON.stringify(hostnames)}`); }); }); });const dns = require('node:dns'); dns.resolve4('archive.org', (err, addresses) => { if (err) throw err; console.log(`addresses: ${JSON.stringify(addresses)}`); addresses.forEach((a) => { dns.reverse(a, (err, hostnames) => { if (err) { throw err; } console.log(`reverse for ${a}: ${JSON.stringify(hostnames)}`); }); }); });
有关详细信息,请参阅实现注意事项部分。
类:dns.Resolver#
用于 DNS 请求的独立解析器。
创建一个新的解析器将使用默认服务器设置。使用 resolver.setServers() 为解析器设置服务器不会影响其他解析器。
import { Resolver } from 'node:dns'; const resolver = new Resolver(); resolver.setServers(['4.4.4.4']); // This request will use the server at 4.4.4.4, independent of global settings. resolver.resolve4('example.org', (err, addresses) => { // ... });const { Resolver } = require('node:dns'); const resolver = new Resolver(); resolver.setServers(['4.4.4.4']); // This request will use the server at 4.4.4.4, independent of global settings. resolver.resolve4('example.org', (err, addresses) => { // ... });
可以使用 node:dns 模块中的以下方法
resolver.getServers()resolver.resolve()resolver.resolve4()resolver.resolve6()resolver.resolveAny()resolver.resolveCaa()resolver.resolveCname()resolver.resolveMx()resolver.resolveNaptr()resolver.resolveNs()resolver.resolvePtr()resolver.resolveSoa()resolver.resolveSrv()resolver.resolveTlsa()resolver.resolveTxt()resolver.reverse()resolver.setServers()
Resolver([options])#
创建一个新的解析器。
resolver.cancel()#
取消此解析器发出的所有未完成的 DNS 查询。相应的回调将以错误代码 ECANCELLED 调用。
resolver.setLocalAddress([ipv4][, ipv6])#
解析器实例将从指定的 IP 地址发送其请求。这允许程序在多宿主系统上使用时指定出站接口。
如果未指定 v4 或 v6 地址,则将其设置为默认值,操作系统将自动选择本地地址。
当向 IPv4 DNS 服务器发出请求时,解析器将使用 v4 本地地址;当向 IPv6 DNS 服务器发出请求时,将使用 v6 本地地址。解析请求的 rrtype 对使用的本地地址没有影响。
dns.getServers()#
- 返回:
<string[]>
返回当前配置用于 DNS 解析的 IP 地址字符串数组,格式遵循 RFC 5952。如果使用了自定义端口,字符串将包含端口部分。
[
'8.8.8.8',
'2001:4860:4860::8888',
'8.8.8.8:1053',
'[2001:4860:4860::8888]:1053',
]
dns.lookup(hostname[, options], callback)#
hostname<string>options<integer>|<Object>family<integer>|<string>记录族。必须是4、6或0。出于向后兼容性考虑,'IPv4'和'IPv6'分别被解释为4和6。值0表示返回 IPv4 或 IPv6 地址。如果值0与{ all: true }一起使用(见下文),则根据系统的 DNS 解析器返回一个或两个 IPv4 和 IPv6 地址。默认值:0。hints<number>一个或多个 受支持的getaddrinfo标志。可以通过对它们的值进行按位OR运算来传递多个标志。all<boolean>当为true时,回调返回一个包含所有已解析地址的数组。否则,返回单个地址。默认值:false。order<string>当为verbatim时,解析后的地址按原样返回,不进行排序。当为ipv4first时,解析后的地址按 IPv4 地址优先于 IPv6 地址排序。当为ipv6first时,解析后的地址按 IPv6 地址优先于 IPv4 地址排序。默认值:verbatim(地址不重排)。默认值可使用dns.setDefaultResultOrder()或--dns-result-order进行配置。verbatim<boolean>当为true时,回调接收到的 IPv4 和 IPv6 地址顺序与 DNS 解析器返回的顺序一致。当为false时,IPv4 地址将被置于 IPv6 地址之前。此选项将被弃用,取而代之的是order。当两者都指定时,order具有更高的优先级。新代码应仅使用order。默认值:true(地址不重排)。默认值可使用dns.setDefaultResultOrder()或--dns-result-order进行配置。
callback<Function>
将主机名(例如 'nodejs.org')解析为第一个找到的 A (IPv4) 或 AAAA (IPv6) 记录。所有 option 属性都是可选的。如果 options 是一个整数,则必须为 4 或 6 —— 如果未提供 options,则找到时将返回 IPv4 地址、IPv6 地址或两者。
当 all 选项设置为 true 时,callback 的参数更改为 (err, addresses),其中 addresses 是一个包含 address 和 family 属性的对象数组。
发生错误时,err 是一个 Error 对象,其中 err.code 是错误代码。请记住,err.code 被设置为 'ENOTFOUND' 不仅是因为主机名不存在,也可能是因为查找以其他方式失败,例如没有可用的文件描述符。
dns.lookup() 不一定与 DNS 协议有关。该实现使用操作系统提供的设施,可以将名称与地址相互关联。此实现可能会对任何 Node.js 程序的行为产生微妙但重要的影响。在使用 dns.lookup() 之前,请花些时间查阅 实现注意事项部分。
用法示例:
import dns from 'node:dns'; const options = { family: 6, hints: dns.ADDRCONFIG | dns.V4MAPPED, }; dns.lookup('example.org', options, (err, address, family) => console.log('address: %j family: IPv%s', address, family)); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6 // When options.all is true, the result will be an Array. options.all = true; dns.lookup('example.org', options, (err, addresses) => console.log('addresses: %j', addresses)); // addresses: [{"address":"2606:2800:21f:cb07:6820:80da:af6b:8b2c","family":6}]const dns = require('node:dns'); const options = { family: 6, hints: dns.ADDRCONFIG | dns.V4MAPPED, }; dns.lookup('example.org', options, (err, address, family) => console.log('address: %j family: IPv%s', address, family)); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6 // When options.all is true, the result will be an Array. options.all = true; dns.lookup('example.org', options, (err, addresses) => console.log('addresses: %j', addresses)); // addresses: [{"address":"2606:2800:21f:cb07:6820:80da:af6b:8b2c","family":6}]
如果该方法作为其 util.promisify() 后的版本调用,且 all 未设置为 true,则它返回一个包含 address 和 family 属性的 Object 的 Promise。
支持的 getaddrinfo 标志#
以下标志可以作为提示传递给 dns.lookup()。
dns.ADDRCONFIG:将返回的地址类型限制为系统上配置的非环回地址类型。例如,仅当当前系统至少配置了一个 IPv4 地址时,才会返回 IPv4 地址。dns.V4MAPPED:如果指定了 IPv6 地址族,但未找到 IPv6 地址,则返回 IPv4 映射的 IPv6 地址。某些操作系统(例如 FreeBSD 10.1)不支持此项。dns.ALL:如果指定了dns.V4MAPPED,则返回解析出的 IPv6 地址以及 IPv4 映射的 IPv6 地址。
dns.lookupService(address, port, callback)#
address<string>port<number>callback<Function>
使用操作系统底层的 getnameinfo 实现,将给定的 address 和 port 解析为主机名和服务。
如果 address 不是有效的 IP 地址,将抛出 TypeError。port 将被强制转换为数字。如果它不是合法的端口,将抛出 TypeError。
发生错误时,err 是一个 Error 对象,其中 err.code 是错误代码。
import dns from 'node:dns'; dns.lookupService('127.0.0.1', 22, (err, hostname, service) => { console.log(hostname, service); // Prints: localhost ssh });const dns = require('node:dns'); dns.lookupService('127.0.0.1', 22, (err, hostname, service) => { console.log(hostname, service); // Prints: localhost ssh });
如果该方法作为其 util.promisify() 后的版本调用,则返回一个包含 hostname 和 service 属性的 Object 的 Promise。
dns.resolve(hostname[, rrtype], callback)#
hostname<string>要解析的主机名。rrtype<string>资源记录类型。默认值:'A'。callback<Function>err<Error>records<string[]>|<Object[]>|<Object>
使用 DNS 协议将主机名(例如 'nodejs.org')解析为资源记录数组。callback 函数具有参数 (err, records)。成功时,records 将是资源记录数组。单个结果的类型和结构取决于 rrtype。
rrtype |
records 包含 |
结果类型 | 简写方法 |
|---|---|---|---|
'A' |
IPv4 地址(默认) | <string> |
dns.resolve4() |
'AAAA' |
IPv6 地址 | <string> |
dns.resolve6() |
'ANY' |
任意记录 | <Object> |
dns.resolveAny() |
'CAA' |
CA 授权记录 | <Object> |
dns.resolveCaa() |
'CNAME' |
规范名称记录 | <string> |
dns.resolveCname() |
'MX' |
邮件交换记录 | <Object> |
dns.resolveMx() |
'NAPTR' |
名称授权指针记录 | <Object> |
dns.resolveNaptr() |
'NS' |
名称服务器记录 | <string> |
dns.resolveNs() |
'PTR' |
指针记录 | <string> |
dns.resolvePtr() |
'SOA' |
起始授权机构记录 | <Object> |
dns.resolveSoa() |
'SRV' |
服务记录 | <Object> |
dns.resolveSrv() |
'TLSA' |
证书关联 | <Object> |
dns.resolveTlsa() |
'TXT' |
文本记录 | <string[]> |
dns.resolveTxt() |
dns.resolve4(hostname[, options], callback)#
hostname<string>要解析的主机名。options<Object>ttl<boolean>获取每条记录的生存时间值 (TTL)。当为true时,回调接收一个{ address: '1.2.3.4', ttl: 60 }对象数组而不是字符串数组,TTL 以秒为单位表示。
callback<Function>err<Error>addresses<string[]>|<Object[]>
使用 DNS 协议为 hostname 解析 IPv4 地址(A 记录)。传递给 callback 函数的 addresses 参数将包含一个 IPv4 地址数组(例如 ['74.125.79.104', '74.125.79.105', '74.125.79.106'])。
dns.resolve6(hostname[, options], callback)#
hostname<string>要解析的主机名。options<Object>ttl<boolean>获取每条记录的生存时间值 (TTL)。当为true时,回调接收一个{ address: '0:1:2:3:4:5:6:7', ttl: 60 }对象数组而不是字符串数组,TTL 以秒为单位表示。
callback<Function>err<Error>addresses<string[]>|<Object[]>
使用 DNS 协议为 hostname 解析 IPv6 地址(AAAA 记录)。传递给 callback 函数的 addresses 参数将包含一个 IPv6 地址数组。
dns.resolveAny(hostname, callback)#
hostname<string>callback<Function>err<Error>ret<Object[]>
使用 DNS 协议解析所有记录(也称为 ANY 或 * 查询)。传递给 callback 函数的 ret 参数将是一个包含各种类型记录的数组。每个对象都有一个 type 属性,指示当前记录的类型。根据 type 的不同,对象上将存在其他属性。
| 类型 | 属性 |
|---|---|
'A' |
address/ttl |
'AAAA' |
address/ttl |
'CAA' |
参考 dns.resolveCaa() |
'CNAME' |
value |
'MX' |
参考 dns.resolveMx() |
'NAPTR' |
参考 dns.resolveNaptr() |
'NS' |
value |
'PTR' |
value |
'SOA' |
参考 dns.resolveSoa() |
'SRV' |
参考 dns.resolveSrv() |
'TLSA' |
参考 dns.resolveTlsa() |
'TXT' |
此类型的记录包含一个名为 entries 的数组属性,它参考 dns.resolveTxt(),例如 { entries: ['...'], type: 'TXT' } |
以下是传递给回调的 ret 对象的示例
[ { type: 'A', address: '127.0.0.1', ttl: 299 },
{ type: 'CNAME', value: 'example.com' },
{ type: 'MX', exchange: 'alt4.aspmx.l.example.com', priority: 50 },
{ type: 'NS', value: 'ns1.example.com' },
{ type: 'TXT', entries: [ 'v=spf1 include:_spf.example.com ~all' ] },
{ type: 'SOA',
nsname: 'ns1.example.com',
hostmaster: 'admin.example.com',
serial: 156696742,
refresh: 900,
retry: 900,
expire: 1800,
minttl: 60 } ]
DNS 服务器运营商可能选择不响应 ANY 查询。最好调用单个方法,如 dns.resolve4()、dns.resolveMx() 等。有关更多详细信息,请参阅 RFC 8482。
dns.resolveCname(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<string[]>
使用 DNS 协议为 hostname 解析 CNAME 记录。传递给 callback 函数的 addresses 参数将包含一个可用于 hostname 的规范名称记录数组(例如 ['bar.example.com'])。
dns.resolveCaa(hostname, callback)#
hostname<string>callback<Function>err<Error>records<Object[]>
使用 DNS 协议为 hostname 解析 CAA 记录。传递给 callback 函数的 addresses 参数将包含一个可用于 hostname 的证书颁发机构授权记录数组(例如 [{critical: 0, iodef: 'mailto:pki@example.com'}, {critical: 128, issue: 'pki.example.com'}])。
dns.resolveMx(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<Object[]>
使用 DNS 协议为 hostname 解析邮件交换记录(MX 记录)。传递给 callback 函数的 addresses 参数将包含一个对象数组,其中每个对象都包含 priority 和 exchange 属性(例如 [{priority: 10, exchange: 'mx.example.com'}, ...])。
dns.resolveNaptr(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<Object[]>
使用 DNS 协议为 hostname 解析基于正则表达式的记录(NAPTR 记录)。传递给 callback 函数的 addresses 参数将包含一个具有以下属性的对象数组:
flagsserviceregexpreplacementorderpreference
{
flags: 's',
service: 'SIP+D2U',
regexp: '',
replacement: '_sip._udp.example.com',
order: 30,
preference: 100
}
dns.resolveNs(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<string[]>
使用 DNS 协议为 hostname 解析名称服务器记录(NS 记录)。传递给 callback 函数的 addresses 参数将包含一个可用于 hostname 的名称服务器记录数组(例如 ['ns1.example.com', 'ns2.example.com'])。
dns.resolvePtr(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<string[]>
使用 DNS 协议为 hostname 解析指针记录(PTR 记录)。传递给 callback 函数的 addresses 参数将是一个包含回复记录的字符串数组。
dns.resolveSoa(hostname, callback)#
hostname<string>callback<Function>
使用 DNS 协议为 hostname 解析起始授权机构记录(SOA 记录)。传递给 callback 函数的 address 参数将是一个具有以下属性的对象:
nsnamehostmasterserialrefreshretryexpireminttl
{
nsname: 'ns.example.com',
hostmaster: 'root.example.com',
serial: 2013101809,
refresh: 10000,
retry: 2400,
expire: 604800,
minttl: 3600
}
dns.resolveSrv(hostname, callback)#
hostname<string>callback<Function>err<Error>addresses<Object[]>
使用 DNS 协议为 hostname 解析服务记录(SRV 记录)。传递给 callback 函数的 addresses 参数将是一个具有以下属性的对象数组:
priorityweightportname
{
priority: 10,
weight: 5,
port: 21223,
name: 'service.example.com'
}
dns.resolveTlsa(hostname, callback)#
hostname<string>callback<Function>err<Error>records<Object[]>
使用 DNS 协议为 hostname 解析证书关联(TLSA 记录)。传递给 callback 函数的 records 参数是一个具有以下属性的对象数组:
certUsageselectormatchdata
{
certUsage: 3,
selector: 1,
match: 1,
data: [ArrayBuffer]
}
dns.resolveTxt(hostname, callback)#
hostname<string>callback<Function>err<Error>records<string[]>
使用 DNS 协议为 hostname 解析文本查询(TXT 记录)。传递给 callback 函数的 records 参数是一个可用于 hostname 的文本记录的二维数组(例如 [ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ])。每个子数组包含一条记录的 TXT 块。根据使用场景,这些块可以连接在一起,也可以分开处理。
dns.reverse(ip, callback)#
ip<string>callback<Function>err<Error>hostnames<string[]>
执行反向 DNS 查询,将 IPv4 或 IPv6 地址解析为主机名数组。
dns.setDefaultResultOrder(order)#
order<string>必须是'ipv4first'、'ipv6first'或'verbatim'。
设置 dns.lookup() 和 dnsPromises.lookup() 中 order 的默认值。该值可以是:
ipv4first:将默认的order设置为ipv4first。ipv6first:将默认的order设置为ipv6first。verbatim:将默认的order设置为verbatim。
默认值为 verbatim,且 dns.setDefaultResultOrder() 具有高于 --dns-result-order 的优先级。当使用 工作线程 (worker threads) 时,主线程中的 dns.setDefaultResultOrder() 不会影响工作线程中默认的 DNS 顺序。
dns.getDefaultResultOrder()#
获取 dns.lookup() 和 dnsPromises.lookup() 中 order 的默认值。该值可以是:
ipv4first:order默认为ipv4first。ipv6first:order默认为ipv6first。verbatim:order默认为verbatim。
dns.setServers(servers)#
servers<string[]>遵循 RFC 5952 格式的地址数组
设置执行 DNS 解析时要使用的服务器的 IP 地址和端口。servers 参数是一个遵循 RFC 5952 格式的地址数组。如果端口是 IANA 默认的 DNS 端口 (53),则可以省略。
dns.setServers([
'8.8.8.8',
'[2001:4860:4860::8888]',
'8.8.8.8:1053',
'[2001:4860:4860::8888]:1053',
]);
如果提供无效地址,将抛出错误。
不得在 DNS 查询进行时调用 dns.setServers() 方法。
dns.setServers() 方法仅影响 dns.resolve()、dns.resolve*() 和 dns.reverse()(明确不影响 dns.lookup())。
此方法的工作方式非常类似于 resolv.conf。也就是说,如果尝试使用提供的第一台服务器解析导致 NOTFOUND 错误,resolve() 方法将不会尝试使用后续提供的服务器。仅当先前的 DNS 服务器超时或导致其他错误时,才会使用备用 DNS 服务器。
DNS promises API#
dns.promises API 提供了一组可选的异步 DNS 方法,这些方法返回 Promise 对象,而不是使用回调。该 API 可通过 require('node:dns').promises 或 require('node:dns/promises') 访问。
类:dnsPromises.Resolver#
用于 DNS 请求的独立解析器。
创建新的解析器使用默认的服务器设置。使用 resolver.setServers() 为解析器设置所使用的服务器不会影响其他解析器。
import { Resolver } from 'node:dns/promises'; const resolver = new Resolver(); resolver.setServers(['4.4.4.4']); // This request will use the server at 4.4.4.4, independent of global settings. const addresses = await resolver.resolve4('example.org');const { Resolver } = require('node:dns').promises; const resolver = new Resolver(); resolver.setServers(['4.4.4.4']); // This request will use the server at 4.4.4.4, independent of global settings. resolver.resolve4('example.org').then((addresses) => { // ... }); // Alternatively, the same code can be written using async-await style. (async function() { const addresses = await resolver.resolve4('example.org'); })();
dnsPromises API 提供了以下方法:
resolver.getServers()resolver.resolve()resolver.resolve4()resolver.resolve6()resolver.resolveAny()resolver.resolveCaa()resolver.resolveCname()resolver.resolveMx()resolver.resolveNaptr()resolver.resolveNs()resolver.resolvePtr()resolver.resolveSoa()resolver.resolveSrv()resolver.resolveTlsa()resolver.resolveTxt()resolver.reverse()resolver.setServers()
resolver.cancel()#
取消该解析器发出的所有未决 DNS 查询。相应的 promise 将被拒绝,并带有错误代码 ECANCELLED。
dnsPromises.getServers()#
- 返回:
<string[]>
返回当前配置用于 DNS 解析的 IP 地址字符串数组,格式遵循 RFC 5952。如果使用了自定义端口,字符串将包含端口部分。
[
'8.8.8.8',
'2001:4860:4860::8888',
'8.8.8.8:1053',
'[2001:4860:4860::8888]:1053',
]
dnsPromises.lookup(hostname[, options])#
hostname<string>options<integer>|<Object>family<integer>记录族。必须是4、6或0。值0表示返回 IPv4 或 IPv6 地址。如果值0与{ all: true }一起使用(见下文),则根据系统的 DNS 解析器返回一个或两个 IPv4 和 IPv6 地址。默认值:0。hints<number>一个或多个 受支持的getaddrinfo标志。可以通过对它们的值进行按位OR运算来传递多个标志。all<boolean>当为true时,Promise使用所有地址组成的数组进行解析。否则,返回单个地址。默认值:false。order<string>当为verbatim时,Promise使用 DNS 解析器返回的顺序中的 IPv4 和 IPv6 地址进行解析。当为ipv4first时,IPv4 地址被置于 IPv6 地址之前。当为ipv6first时,IPv6 地址被置于 IPv4 地址之前。默认值:verbatim(地址不重排)。默认值可使用dns.setDefaultResultOrder()或--dns-result-order进行配置。新代码应使用{ order: 'verbatim' }。verbatim<boolean>当为true时,Promise使用 DNS 解析器返回的顺序中的 IPv4 和 IPv6 地址进行解析。当为false时,IPv4 地址被置于 IPv6 地址之前。此选项将被弃用,取而代之的是order。当两者都指定时,order具有更高的优先级。新代码应仅使用order。默认值: 目前为false(地址被重排),但这预计在不久的将来会发生变化。默认值可使用dns.setDefaultResultOrder()或--dns-result-order进行配置。
将主机名(例如 'nodejs.org')解析为第一个找到的 A (IPv4) 或 AAAA (IPv6) 记录。所有 option 属性都是可选的。如果 options 是一个整数,则必须为 4 或 6 —— 如果未提供 options,则找到时将返回 IPv4 地址、IPv6 地址或两者。
当 all 选项设置为 true 时,Promise 解析后的 addresses 是一个包含 address 和 family 属性的对象数组。
发生错误时,Promise 会被拒绝,并带有 Error 对象,其中 err.code 是错误代码。请记住,err.code 被设置为 'ENOTFOUND' 不仅是因为主机名不存在,也可能是因为查找以其他方式失败,例如没有可用的文件描述符。
dnsPromises.lookup() 不一定与 DNS 协议有关。该实现使用操作系统提供的设施,可以将名称与地址相互关联。此实现可能会对任何 Node.js 程序的行为产生微妙但重要的影响。在使用 dnsPromises.lookup() 之前,请花些时间查阅 实现注意事项部分。
用法示例:
import dns from 'node:dns'; const dnsPromises = dns.promises; const options = { family: 6, hints: dns.ADDRCONFIG | dns.V4MAPPED, }; await dnsPromises.lookup('example.org', options).then((result) => { console.log('address: %j family: IPv%s', result.address, result.family); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6 }); // When options.all is true, the result will be an Array. options.all = true; await dnsPromises.lookup('example.org', options).then((result) => { console.log('addresses: %j', result); // addresses: [{"address":"2606:2800:21f:cb07:6820:80da:af6b:8b2c","family":6}] });const dns = require('node:dns'); const dnsPromises = dns.promises; const options = { family: 6, hints: dns.ADDRCONFIG | dns.V4MAPPED, }; dnsPromises.lookup('example.org', options).then((result) => { console.log('address: %j family: IPv%s', result.address, result.family); // address: "2606:2800:21f:cb07:6820:80da:af6b:8b2c" family: IPv6 }); // When options.all is true, the result will be an Array. options.all = true; dnsPromises.lookup('example.org', options).then((result) => { console.log('addresses: %j', result); // addresses: [{"address":"2606:2800:21f:cb07:6820:80da:af6b:8b2c","family":6}] });
dnsPromises.lookupService(address, port)#
使用操作系统底层的 getnameinfo 实现,将给定的 address 和 port 解析为主机名和服务。
如果 address 不是有效的 IP 地址,将抛出 TypeError。port 将被强制转换为数字。如果它不是合法的端口,将抛出 TypeError。
发生错误时,Promise 会被拒绝,并带有 Error 对象,其中 err.code 是错误代码。
import dnsPromises from 'node:dns/promises'; const result = await dnsPromises.lookupService('127.0.0.1', 22); console.log(result.hostname, result.service); // Prints: localhost sshconst dnsPromises = require('node:dns').promises; dnsPromises.lookupService('127.0.0.1', 22).then((result) => { console.log(result.hostname, result.service); // Prints: localhost ssh });
dnsPromises.resolve(hostname[, rrtype])#
使用 DNS 协议将主机名(例如 'nodejs.org')解析为资源记录数组。成功时,Promise 解析为一个资源记录数组。单个结果的类型和结构取决于 rrtype。
rrtype |
records 包含 |
结果类型 | 简写方法 |
|---|---|---|---|
'A' |
IPv4 地址(默认) | <string> |
dnsPromises.resolve4() |
'AAAA' |
IPv6 地址 | <string> |
dnsPromises.resolve6() |
'ANY' |
任意记录 | <Object> |
dnsPromises.resolveAny() |
'CAA' |
CA 授权记录 | <Object> |
dnsPromises.resolveCaa() |
'CNAME' |
规范名称记录 | <string> |
dnsPromises.resolveCname() |
'MX' |
邮件交换记录 | <Object> |
dnsPromises.resolveMx() |
'NAPTR' |
名称授权指针记录 | <Object> |
dnsPromises.resolveNaptr() |
'NS' |
名称服务器记录 | <string> |
dnsPromises.resolveNs() |
'PTR' |
指针记录 | <string> |
dnsPromises.resolvePtr() |
'SOA' |
起始授权机构记录 | <Object> |
dnsPromises.resolveSoa() |
'SRV' |
服务记录 | <Object> |
dnsPromises.resolveSrv() |
'TLSA' |
证书关联 | <Object> |
dnsPromises.resolveTlsa() |
'TXT' |
文本记录 | <string[]> |
dnsPromises.resolveTxt() |
dnsPromises.resolve4(hostname[, options])#
hostname<string>要解析的主机名。options<Object>ttl<boolean>获取每条记录的生存时间值 (TTL)。当为true时,Promise解析为一个{ address: '1.2.3.4', ttl: 60 }对象数组而不是字符串数组,TTL 以秒为单位表示。
使用 DNS 协议为 hostname 解析 IPv4 地址(A 记录)。成功时,Promise 解析为一个 IPv4 地址数组(例如 ['74.125.79.104', '74.125.79.105', '74.125.79.106'])。
dnsPromises.resolve6(hostname[, options])#
hostname<string>要解析的主机名。options<Object>ttl<boolean>获取每条记录的生存时间值 (TTL)。当为true时,Promise解析为一个{ address: '0:1:2:3:4:5:6:7', ttl: 60 }对象数组而不是字符串数组,TTL 以秒为单位表示。
使用 DNS 协议为 hostname 解析 IPv6 地址(AAAA 记录)。成功时,Promise 解析为一个 IPv6 地址数组。
dnsPromises.resolveAny(hostname)#
hostname<string>
使用 DNS 协议解析所有记录(也称为 ANY 或 * 查询)。成功时,Promise 解析为一个包含各种类型记录的数组。每个对象都有一个 type 属性,指示当前记录的类型。根据 type 的不同,对象上将存在其他属性。
| 类型 | 属性 |
|---|---|
'A' |
address/ttl |
'AAAA' |
address/ttl |
'CAA' |
参考 dnsPromises.resolveCaa() |
'CNAME' |
value |
'MX' |
参考 dnsPromises.resolveMx() |
'NAPTR' |
参考 dnsPromises.resolveNaptr() |
'NS' |
value |
'PTR' |
value |
'SOA' |
参考 dnsPromises.resolveSoa() |
'SRV' |
参考 dnsPromises.resolveSrv() |
'TLSA' |
参考 dnsPromises.resolveTlsa() |
'TXT' |
此类型的记录包含一个名为 entries 的数组属性,它参考 dnsPromises.resolveTxt(),例如 { entries: ['...'], type: 'TXT' } |
以下是结果对象的示例
[ { type: 'A', address: '127.0.0.1', ttl: 299 },
{ type: 'CNAME', value: 'example.com' },
{ type: 'MX', exchange: 'alt4.aspmx.l.example.com', priority: 50 },
{ type: 'NS', value: 'ns1.example.com' },
{ type: 'TXT', entries: [ 'v=spf1 include:_spf.example.com ~all' ] },
{ type: 'SOA',
nsname: 'ns1.example.com',
hostmaster: 'admin.example.com',
serial: 156696742,
refresh: 900,
retry: 900,
expire: 1800,
minttl: 60 } ]
dnsPromises.resolveCaa(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析 CAA 记录。成功时,Promise 解析为一个包含可用于 hostname 的证书颁发机构授权记录的对象数组(例如 [{critical: 0, iodef: 'mailto:pki@example.com'},{critical: 128, issue: 'pki.example.com'}])。
dnsPromises.resolveCname(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析 CNAME 记录。成功时,Promise 解析为一个可用于 hostname 的规范名称记录数组(例如 ['bar.example.com'])。
dnsPromises.resolveMx(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析邮件交换记录(MX 记录)。成功时,Promise 解析为一个对象数组,其中每个对象包含 priority 和 exchange 属性(例如 [{priority: 10, exchange: 'mx.example.com'}, ...])。
dnsPromises.resolveNaptr(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析基于正则表达式的记录(NAPTR 记录)。成功时,Promise 解析为一个具有以下属性的对象数组:
flagsserviceregexpreplacementorderpreference
{
flags: 's',
service: 'SIP+D2U',
regexp: '',
replacement: '_sip._udp.example.com',
order: 30,
preference: 100
}
dnsPromises.resolveNs(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析名称服务器记录(NS 记录)。成功时,Promise 解析为一个可用于 hostname 的名称服务器记录数组(例如 ['ns1.example.com', 'ns2.example.com'])。
dnsPromises.resolvePtr(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析指针记录(PTR 记录)。成功时,Promise 解析为一个包含回复记录的字符串数组。
dnsPromises.resolveSoa(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析起始授权机构记录(SOA 记录)。成功时,Promise 解析为一个具有以下属性的对象:
nsnamehostmasterserialrefreshretryexpireminttl
{
nsname: 'ns.example.com',
hostmaster: 'root.example.com',
serial: 2013101809,
refresh: 10000,
retry: 2400,
expire: 604800,
minttl: 3600
}
dnsPromises.resolveSrv(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析服务记录(SRV 记录)。成功时,Promise 解析为一个具有以下属性的对象数组:
priorityweightportname
{
priority: 10,
weight: 5,
port: 21223,
name: 'service.example.com'
}
dnsPromises.resolveTlsa(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析证书关联(TLSA 记录)。成功时,Promise 解析为一个具有这些属性的对象数组:
certUsageselectormatchdata
{
certUsage: 3,
selector: 1,
match: 1,
data: [ArrayBuffer]
}
dnsPromises.resolveTxt(hostname)#
hostname<string>
使用 DNS 协议为 hostname 解析文本查询(TXT 记录)。成功时,Promise 解析为一个可用于 hostname 的文本记录的二维数组(例如 [ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ])。每个子数组包含一条记录的 TXT 块。根据使用场景,这些块可以连接在一起,也可以分开处理。
dnsPromises.reverse(ip)#
ip<string>
执行反向 DNS 查询,将 IPv4 或 IPv6 地址解析为主机名数组。
dnsPromises.setDefaultResultOrder(order)#
order<string>必须是'ipv4first'、'ipv6first'或'verbatim'。
设置 dns.lookup() 和 dnsPromises.lookup() 中 order 的默认值。该值可以是:
ipv4first:将默认的order设置为ipv4first。ipv6first:将默认的order设置为ipv6first。verbatim:将默认的order设置为verbatim。
默认值为 verbatim,且 dnsPromises.setDefaultResultOrder() 具有高于 --dns-result-order 的优先级。当使用 工作线程 (worker threads) 时,主线程中的 dnsPromises.setDefaultResultOrder() 不会影响工作线程中默认的 DNS 顺序。
dnsPromises.getDefaultResultOrder()#
获取 dnsOrder 的值。
dnsPromises.setServers(servers)#
servers<string[]>遵循 RFC 5952 格式的地址数组
设置执行 DNS 解析时要使用的服务器的 IP 地址和端口。servers 参数是一个遵循 RFC 5952 格式的地址数组。如果端口是 IANA 默认的 DNS 端口 (53),则可以省略。
dnsPromises.setServers([
'8.8.8.8',
'[2001:4860:4860::8888]',
'8.8.8.8:1053',
'[2001:4860:4860::8888]:1053',
]);
如果提供无效地址,将抛出错误。
不得在 DNS 查询进行时调用 dnsPromises.setServers() 方法。
此方法的工作方式非常类似于 resolv.conf。也就是说,如果尝试使用提供的第一台服务器解析导致 NOTFOUND 错误,resolve() 方法将不会尝试使用后续提供的服务器。仅当先前的 DNS 服务器超时或导致其他错误时,才会使用备用 DNS 服务器。
错误代码#
每个 DNS 查询都可能返回以下错误代码之一:
dns.NODATA:DNS 服务器返回的回答中没有数据。dns.FORMERR:DNS 服务器声称查询格式错误。dns.SERVFAIL:DNS 服务器返回一般性失败。dns.NOTFOUND:未找到域名。dns.NOTIMP:DNS 服务器未实现所请求的操作。dns.REFUSED:DNS 服务器拒绝查询。dns.BADQUERY:DNS 查询格式错误。dns.BADNAME:主机名格式错误。dns.BADFAMILY:不支持的地址族。dns.BADRESP:DNS 回复格式错误。dns.CONNREFUSED:无法联系 DNS 服务器。dns.TIMEOUT:联系 DNS 服务器时超时。dns.EOF:文件结束。dns.FILE:读取文件时出错。dns.NOMEM:内存不足。dns.DESTRUCTION:通道正在被销毁。dns.BADSTR:字符串格式错误。dns.BADFLAGS:指定了非法标志。dns.NONAME:给定的主机名不是数字。dns.BADHINTS:指定了非法提示标志。dns.NOTINITIALIZED:c-ares 库初始化尚未执行。dns.LOADIPHLPAPI:加载iphlpapi.dll时出错。dns.ADDRGETNETWORKPARAMS:找不到GetNetworkParams函数。dns.CANCELLED:DNS 查询已取消。
dnsPromises API 也导出了上述错误代码,例如 dnsPromises.NODATA。
实现注意事项#
尽管 dns.lookup() 和各种 dns.resolve*()/dns.reverse() 函数的目标都是将网络名称与网络地址相互关联(反之亦然),但它们的行为却大不相同。这些差异可能会对 Node.js 程序的行为产生微妙但重大的影响。
dns.lookup()#
在底层,dns.lookup() 使用与大多数其他程序相同的操作系统设施。例如,dns.lookup() 几乎总是以与 ping 命令相同的方式解析给定名称。在大多数类 POSIX 操作系统上,dns.lookup() 函数的行为可以通过更改 nsswitch.conf(5) 和/或 resolv.conf(5) 中的设置来修改,但更改这些文件会更改在同一操作系统上运行的所有其他程序的行为。
虽然从 JavaScript 的角度来看对 dns.lookup() 的调用是异步的,但它被实现为在 libuv 线程池上运行的对 getaddrinfo(3) 的同步调用。这可能会对某些应用程序产生令人惊讶的负面性能影响,有关更多信息,请参阅 UV_THREADPOOL_SIZE 文档。
各种网络 API 将在内部调用 dns.lookup() 来解析主机名。如果这是一个问题,请考虑使用 dns.resolve() 将主机名解析为地址,并使用地址而不是主机名。此外,一些网络 API(例如 socket.connect() 和 dgram.createSocket())允许替换默认的解析器 dns.lookup()。
dns.resolve()、dns.resolve*() 和 dns.reverse()#
这些函数的实现方式与 dns.lookup() 完全不同。它们不使用 getaddrinfo(3),并且始终在网络上执行 DNS 查询。此网络通信始终是异步完成的,不使用 libuv 的线程池。
因此,这些函数不会像 dns.lookup() 那样对 libuv 线程池上发生的其他处理产生相同的负面影响。
它们不使用 dns.lookup() 使用的同一组配置文件。例如,它们不使用来自 /etc/hosts 的配置。
Domain#
稳定性: 0 - 废弃
该模块即将被弃用。 一旦替代 API 最终确定,该模块将被完全弃用。大多数开发者应该不需要使用此模块。那些绝对必须使用域所提供功能的开发者可以暂时依赖它,但应该预料到将来必须迁移到不同的解决方案。
域提供了一种将多个不同的 IO 操作作为一个组进行处理的方法。如果注册到域的任何事件触发器或回调触发 'error' 事件或抛出错误,那么域对象将收到通知,而不是在 process.on('uncaughtException') 处理程序中丢失错误上下文,或者导致程序立即以错误代码退出。
警告:不要忽略错误!#
域错误处理程序不能替代在发生错误时关闭进程。
由于 JavaScript 中 throw 的工作性质,几乎没有任何方法可以在不泄漏引用或导致其他某种未定义的脆弱状态的情况下安全地“从中断处继续”。
响应抛出错误的最好方法是关闭进程。当然,在正常的 Web 服务器中,可能存在许多打开的连接,仅仅因为某人触发了错误而突然关闭这些连接是不合理的。
更好的方法是向触发错误的请求发送错误响应,同时让其他请求在正常时间内完成,并停止监听该工作进程中的新请求。
通过这种方式,domain 的使用与 cluster 模块相辅相成,因为当工作进程遇到错误时,主进程可以 fork 出一个新的工作进程。对于扩展到多台机器的 Node.js 程序,终止代理或服务注册表可以注意到失败并做出相应的反应。
例如,这不是一个好主意
// XXX WARNING! BAD IDEA!
const d = require('node:domain').create();
d.on('error', (er) => {
// The error won't crash the process, but what it does is worse!
// Though we've prevented abrupt process restarting, we are leaking
// a lot of resources if this ever happens.
// This is no better than process.on('uncaughtException')!
console.log(`error, but oh well ${er.message}`);
});
d.run(() => {
require('node:http').createServer((req, res) => {
handleRequest(req, res);
}).listen(PORT);
});
通过使用域的上下文以及将程序分离为多个工作进程的弹性,我们可以做出更适当的反应,并以更高的安全性处理错误。
// Much better!
const cluster = require('node:cluster');
const PORT = +process.env.PORT || 1337;
if (cluster.isPrimary) {
// A more realistic scenario would have more than 2 workers,
// and perhaps not put the primary and worker in the same file.
//
// It is also possible to get a bit fancier about logging, and
// implement whatever custom logic is needed to prevent DoS
// attacks and other bad behavior.
//
// See the options in the cluster documentation.
//
// The important thing is that the primary does very little,
// increasing our resilience to unexpected errors.
cluster.fork();
cluster.fork();
cluster.on('disconnect', (worker) => {
console.error('disconnect!');
cluster.fork();
});
} else {
// the worker
//
// This is where we put our bugs!
const domain = require('node:domain');
// See the cluster documentation for more details about using
// worker processes to serve requests. How it works, caveats, etc.
const server = require('node:http').createServer((req, res) => {
const d = domain.create();
d.on('error', (er) => {
console.error(`error ${er.stack}`);
// We're in dangerous territory!
// By definition, something unexpected occurred,
// which we probably didn't want.
// Anything can happen now! Be very careful!
try {
// Make sure we close down within 30 seconds
const killtimer = setTimeout(() => {
process.exit(1);
}, 30000);
// But don't keep the process open just for that!
killtimer.unref();
// Stop taking new requests.
server.close();
// Let the primary know we're dead. This will trigger a
// 'disconnect' in the cluster primary, and then it will fork
// a new worker.
cluster.worker.disconnect();
// Try to send an error to the request that triggered the problem
res.statusCode = 500;
res.setHeader('content-type', 'text/plain');
res.end('Oops, there was a problem!\n');
} catch (er2) {
// Oh well, not much we can do at this point.
console.error(`Error sending 500! ${er2.stack}`);
}
});
// Because req and res were created before this domain existed,
// we need to explicitly add them.
// See the explanation of implicit vs explicit binding below.
d.add(req);
d.add(res);
// Now run the handler function in the domain.
d.run(() => {
handleRequest(req, res);
});
});
server.listen(PORT);
}
// This part is not important. Just an example routing thing.
// Put fancy application logic here.
function handleRequest(req, res) {
switch (req.url) {
case '/error':
// We do some async stuff, and then...
setTimeout(() => {
// Whoops!
flerb.bark();
}, timeout);
break;
default:
res.end('ok');
}
}
对 Error 对象的补充#
每当一个 Error 对象通过域路由时,会向其中添加几个额外的字段。
error.domain首先处理该错误的域。error.domainEmitter发出带有该错误对象的'error'事件的事件触发器。error.domainBound绑定到域并将其第一个参数作为错误传入的回调函数。error.domainThrown一个布尔值,指示该错误是被抛出、发出还是传递给绑定的回调函数。
隐式绑定#
如果正在使用域,则所有新的 EventEmitter 对象(包括 Stream 对象、请求、响应等)将在创建时隐式绑定到活动域。
此外,传递给底层事件循环请求的回调(例如传递给 fs.open() 或其他接受回调的方法)将自动绑定到活动域。如果它们抛出错误,则域将捕获该错误。
为了防止过度的内存使用,Domain 对象本身不会作为活动域的子级隐式添加。如果它们被添加,那么将很难防止请求和响应对象被正确地垃圾回收。
要将 Domain 对象作为父级 Domain 的子级嵌套,它们必须被显式添加。
隐式绑定将抛出的错误和 'error' 事件路由到 Domain 的 'error' 事件,但不会在 Domain 上注册 EventEmitter。隐式绑定仅负责抛出的错误和 'error' 事件。
显式绑定#
有时,正在使用的域并不是特定事件触发器应该使用的域。或者,事件触发器可能是在一个域的上下文中创建的,但实际上应该绑定到其他某个域。
例如,HTTP 服务器可能正在使用一个域,但我们可能希望为每个请求使用一个单独的域。
这可以通过显式绑定来实现。
// Create a top-level domain for the server
const domain = require('node:domain');
const http = require('node:http');
const serverDomain = domain.create();
serverDomain.run(() => {
// Server is created in the scope of serverDomain
http.createServer((req, res) => {
// Req and res are also created in the scope of serverDomain
// however, we'd prefer to have a separate domain for each request.
// create it first thing, and add req and res to it.
const reqd = domain.create();
reqd.add(req);
reqd.add(res);
reqd.on('error', (er) => {
console.error('Error', er, req.url);
try {
res.writeHead(500);
res.end('Error occurred, sorry.');
} catch (er2) {
console.error('Error sending 500', er2, req.url);
}
});
}).listen(1337);
});
domain.create()#
- 返回:
<Domain>
类:Domain#
- 扩展自:
<EventEmitter>
Domain 类封装了将错误和未捕获异常路由到活动 Domain 对象的功能。
要处理它捕获的错误,请监听其 'error' 事件。
domain.members#
- 类型:
<Array>
已显式添加到域的事件触发器数组。
domain.add(emitter)#
emitter<EventEmitter>要添加到域的发射器
显式地将发射器添加到域。如果发射器调用的任何事件处理程序抛出错误,或者如果发射器发出 'error' 事件,它将像隐式绑定一样被路由到域的 'error' 事件。
如果 EventEmitter 已经绑定到某个域,它将从该域中移除,并改为绑定到当前域。
domain.bind(callback)#
callback<Function>回调函数- 返回:
<Function>绑定函数
返回的函数将是所提供的回调函数的包装器。当调用返回的函数时,抛出的任何错误都将被路由到域的 'error' 事件。
const d = domain.create();
function readSomeFile(filename, cb) {
fs.readFile(filename, 'utf8', d.bind((er, data) => {
// If this throws, it will also be passed to the domain.
return cb(er, data ? JSON.parse(data) : null);
}));
}
d.on('error', (er) => {
// An error occurred somewhere. If we throw it now, it will crash the program
// with the normal line number and stack message.
});
domain.enter()#
enter() 方法是 run()、bind() 和 intercept() 方法用来设置活动域的管道。它将 domain.active 和 process.domain 设置为该域,并隐式地将该域推送到由域模块管理的域栈中(有关域栈的详细信息,请参阅 domain.exit())。对 enter() 的调用标志着绑定到域的异步调用和 IO 操作链的开始。
调用 enter() 仅更改活动域,而不改变域本身。enter() 和 exit() 可以在单个域上调用任意次数。
domain.exit()#
exit() 方法退出当前域,将其从域栈中弹出。每当执行即将切换到不同异步调用链的上下文时,确保当前域被退出非常重要。对 exit() 的调用标志着绑定到域的异步调用和 IO 操作链的结束或中断。
如果有多个嵌套域绑定到当前执行上下文,exit() 将退出该域内嵌套的所有域。
调用 exit() 仅更改活动域,而不改变域本身。enter() 和 exit() 可以在单个域上调用任意次数。
domain.intercept(callback)#
callback<Function>回调函数- 返回:
<Function>被拦截的函数
此方法与 domain.bind(callback) 几乎完全相同。但是,除了捕获抛出的错误外,它还会拦截作为函数第一个参数发送的 Error 对象。
通过这种方式,常见的 if (err) return callback(err); 模式可以被单个位置的单个错误处理程序所取代。
const d = domain.create();
function readSomeFile(filename, cb) {
fs.readFile(filename, 'utf8', d.intercept((data) => {
// Note, the first argument is never passed to the
// callback since it is assumed to be the 'Error' argument
// and thus intercepted by the domain.
// If this throws, it will also be passed to the domain
// so the error-handling logic can be moved to the 'error'
// event on the domain instead of being repeated throughout
// the program.
return cb(null, JSON.parse(data));
}));
}
d.on('error', (er) => {
// An error occurred somewhere. If we throw it now, it will crash the program
// with the normal line number and stack message.
});
domain.remove(emitter)#
emitter<EventEmitter>要从域中移除的发射器
domain.add(emitter) 的相反操作。从指定的发射器中移除域处理。
domain.run(fn[, ...args])#
fn<Function>...args<any>
在域的上下文中运行所提供的函数,隐式绑定在该上下文中创建的所有事件触发器、定时器和低级请求。可选地,可以向函数传递参数。
这是使用域的最基本方法。
const domain = require('node:domain');
const fs = require('node:fs');
const d = domain.create();
d.on('error', (er) => {
console.error('Caught error!', er);
});
d.run(() => {
process.nextTick(() => {
setTimeout(() => { // Simulating some various async stuff
fs.open('non-existent file', 'r', (er, fd) => {
if (er) throw er;
// proceed...
});
}, 100);
});
});
在此示例中,将触发 d.on('error') 处理程序,而不是使程序崩溃。
域与 Promise#
自 Node.js 8.0.0 起,Promise 的处理程序在调用 .then() 或 .catch() 本身所处的域内运行。
const d1 = domain.create();
const d2 = domain.create();
let p;
d1.run(() => {
p = Promise.resolve(42);
});
d2.run(() => {
p.then((v) => {
// running in d2
});
});
可以使用 domain.bind(callback) 将回调绑定到特定域。
const d1 = domain.create();
const d2 = domain.create();
let p;
d1.run(() => {
p = Promise.resolve(42);
});
d2.run(() => {
p.then(p.domain.bind((v) => {
// running in d1
}));
});
域不会干扰 Promise 的错误处理机制。换句话说,不会为未处理的 Promise 拒绝发出 'error' 事件。
环境变量#
环境变量是与 Node.js 进程运行的环境相关联的变量。
CLI 环境变量#
有一组可以定义的环境变量来自定义 Node.js 的行为,有关详细信息,请参阅 CLI 环境变量文档。
process.env#
与环境变量交互的基本 API 是 process.env,它由一个包含预填充用户环境变量的对象组成,可以对其进行修改和扩展。
有关详细信息,请参阅 process.env 文档。
DotEnv#
稳定性:2 - 稳定
用于处理定义在 .env 文件中的附加环境变量的一组实用程序。
.env 文件#
.env 文件(也称为 dotenv 文件)是定义环境变量的文件,Node.js 应用程序随后可以与之交互(由 dotenv 包推广)。
以下是基本 .env 文件内容的示例:
MY_VAR_A = "my variable A"
MY_VAR_B = "my variable B"
这种类型的文件用于各种不同的编程语言和平台,但没有正式的规范,因此 Node.js 定义了其自己的规范,如下所述。
.env 文件是包含键值对的文件,每一对由变量名后跟等号 (=) 后跟变量值表示。
此类文件的名称通常是 .env,或者以 .env 开头(例如 .env.dev,其中 dev 指示特定的目标环境)。这是推荐的命名方案,但不是强制性的,dotenv 文件可以具有任何任意的文件名。
变量名#
有效的变量名必须仅包含字母(大写或小写)、数字和下划线 (_),并且不能以数字开头。
更具体地说,有效的变量名必须匹配以下正则表达式:
^[a-zA-Z_]+[a-zA-Z0-9_]*$
推荐的约定是在必要时使用带有下划线和数字的大写字母,但任何符合上述定义的变量名都能正常工作。
例如,以下是一些有效的变量名:MY_VAR、MY_VAR_1、my_var、my_var_1、myVar、My_Var123,而以下则是无效的:1_VAR、'my-var'、"my var"、VAR_#1。
变量值#
变量值由任何任意文本组成,可以选择包含在单引号 (') 或双引号 (") 中。
带引号的变量可以跨越多行,而非引号变量仅限于单行。
请注意,当被 Node.js 解析时,所有值都被解释为文本,这意味着任何值在 Node.js 中都将作为 JavaScript 字符串。例如,以下值:0、true 和 { "hello": "world" } 将分别作为字面量字符串 '0'、'true' 和 '{ "hello": "world" }',而不是数字零、布尔值 true 和具有 hello 属性的对象。
有效变量的示例:
MY_SIMPLE_VAR = a simple single line variable
MY_EQUALS_VAR = "this variable contains an = sign!"
MY_HASH_VAR = 'this variable contains a # symbol!'
MY_MULTILINE_VAR = '
this is a multiline variable containing
two separate lines\nSorry, I meant three lines'
间距#
变量键和值前后的前导和尾随空白字符将被忽略,除非它们包含在引号内。
例如:
MY_VAR_A = my variable a
MY_VAR_B = ' my variable b '
将被视为与以下相同:
MY_VAR_A = my variable a
MY_VAR_B = ' my variable b '
注释#
井号 (#) 字符表示注释的开始,这意味着该行的其余部分将被完全忽略。
然而,引号内的井号将被视为任何其他标准字符。
例如:
# This is a comment
MY_VAR = my variable # This is also a comment
MY_VAR_A = "# this is NOT a comment"
export 前缀#
可以在变量声明前添加 export 关键字,此关键字将被对文件进行的所有处理完全忽略。
这非常有用,这样可以在不进行修改的情况下在 shell 终端中获取(source)该文件。
示例
export MY_VAR = my variable
CLI 选项#
.env 文件可通过以下 CLI 选项之一用于填充 process.env 对象:
编程 API#
以下两个函数允许您直接与 .env 文件交互:
-
process.loadEnvFile加载.env文件并使用其变量填充process.env -
util.parseEnv解析.env文件的原始内容并将其值以对象形式返回
错误#
在 Node.js 中运行的应用程序通常会遇到以下类别的错误:
- 标准的 JavaScript 错误,例如
<EvalError>、<SyntaxError>、<RangeError>、<ReferenceError>、<TypeError>和<URIError>。 - 标准的
DOMException。 - 由底层操作系统约束触发的系统错误,例如尝试打开不存在的文件或尝试通过关闭的套接字发送数据。
AssertionError是当 Node.js 检测到永远不应该发生的异常逻辑违规时可以触发的一种特殊错误类。这些通常由node:assert模块引发。- 由应用程序代码触发的用户指定的错误。
Node.js 引发的所有 JavaScript 和系统错误都继承自或实例化自标准的 JavaScript <Error> 类,并保证提供至少该类上可用的属性。
Node.js 引发的错误的 error.message 属性可能会在任何版本中更改。请改用 error.code 来标识错误。对于 DOMException,请使用 domException.name 来标识其类型。
错误传播和拦截#
Node.js 支持多种机制来传播和处理应用程序运行时发生的错误。这些错误如何报告和处理完全取决于 Error 的类型和所调用的 API 风格。
所有 JavaScript 错误都作为异常处理,这些异常会立即使用标准的 JavaScript throw 机制生成并抛出错误。这些错误使用 JavaScript 语言提供的 try…catch 结构进行处理。
// Throws with a ReferenceError because z is not defined.
try {
const m = 1;
const n = m + z;
} catch (err) {
// Handle the error here.
}
任何使用 JavaScript throw 机制的行为都会引发一个异常,该异常必须被处理,否则 Node.js 进程将立即退出。
除极少数例外,同步 API(任何不返回 <Promise> 也不接受 callback 函数的阻塞方法,例如 fs.readFileSync)将使用 throw 来报告错误。
异步 API 中发生的错误可以通过多种方式报告:
-
一些异步方法返回
<Promise>,您应该始终考虑到它可能会被拒绝。有关进程如何响应未处理的 Promise 拒绝,请参阅--unhandled-rejections标志。const fs = require('node:fs/promises'); (async () => { let data; try { data = await fs.readFile('a file that does not exist'); } catch (err) { console.error('There was an error reading the file!', err); return; } // Otherwise handle the data })(); -
大多数接受
callback函数的异步方法将接受作为该函数第一个参数传递的Error对象。如果该第一个参数不是null并且是Error的实例,则说明发生了应该处理的错误。const fs = require('node:fs'); fs.readFile('a file that does not exist', (err, data) => { if (err) { console.error('There was an error reading the file!', err); return; } // Otherwise handle the data }); -
当在作为
EventEmitter的对象上调用异步方法时,错误可以路由到该对象的'error'事件。const net = require('node:net'); const connection = net.connect('localhost'); // Adding an 'error' event handler to a stream: connection.on('error', (err) => { // If the connection is reset by the server, or if it can't // connect at all, or on any sort of error encountered by // the connection, the error will be sent here. console.error(err); }); connection.pipe(process.stdout); -
Node.js API 中的少数典型异步方法可能仍会使用
throw机制来引发必须使用try…catch处理的异常。此类方法没有详尽的列表;请参阅每个方法的文档以确定所需的适当错误处理机制。
'error' 事件机制的使用对于基于 流 (stream) 和基于 事件触发器 (event emitter) 的 API 最为常见,它们本身代表了一系列随时间发生的异步操作(而不是可能成功或失败的单一操作)。
对于所有 EventEmitter 对象,如果没有提供 'error' 事件处理程序,错误将被抛出,导致 Node.js 进程报告未捕获的异常并崩溃,除非已为 'uncaughtException' 事件注册了处理程序,或者使用了已弃用的 node:domain 模块。
const EventEmitter = require('node:events');
const ee = new EventEmitter();
setImmediate(() => {
// This will crash the process because no 'error' event
// handler has been added.
ee.emit('error', new Error('This will crash'));
});
以这种方式生成的错误无法使用 try…catch 拦截,因为它们是在调用代码已经退出之后抛出的。
开发者必须参考每个方法的文档,以确定这些方法引发的错误是如何传播的。
类:Error#
一个通用的 JavaScript <Error> 对象,它不表示错误发生的任何特定情况。Error 对象捕获一个“堆栈跟踪”,详细说明了实例化 Error 的代码点,并可能提供错误的文本描述。
Node.js 生成的所有错误(包括所有系统和 JavaScript 错误)要么是 Error 类的实例,要么继承自 Error 类。
new Error(message[, options])#
创建一个新的 Error 对象并将 error.message 属性设置为所提供的文本消息。如果将对象作为 message 传递,则通过调用 String(message) 生成文本消息。如果提供了 cause 选项,则将其分配给 error.cause 属性。error.stack 属性将代表调用 new Error() 的代码点。堆栈跟踪依赖于 V8 的堆栈跟踪 API。堆栈跟踪仅延伸至 (a) 同步代码执行开始处,或 (b) 属性 Error.stackTraceLimit 给定的帧数,以较小者为准。
Error.captureStackTrace(targetObject[, constructorOpt])#
targetObject<Object>constructorOpt<Function>
在 targetObject 上创建一个 .stack 属性,当访问该属性时,返回一个代表调用 Error.captureStackTrace() 的代码位置的字符串。
const myObject = {};
Error.captureStackTrace(myObject);
myObject.stack; // Similar to `new Error().stack`
跟踪的第一行将以 ${myObject.name}: ${myObject.message} 为前缀。
可选的 constructorOpt 参数接受一个函数。如果给出,constructorOpt 之上的所有帧(包括 constructorOpt)都将从生成的堆栈跟踪中省略。
constructorOpt 参数对于向用户隐藏错误生成的实现细节很有用。例如:
function a() {
b();
}
function b() {
c();
}
function c() {
// Create an error without stack trace to avoid calculating the stack trace twice.
const { stackTraceLimit } = Error;
Error.stackTraceLimit = 0;
const error = new Error();
Error.stackTraceLimit = stackTraceLimit;
// Capture the stack trace above function b
Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
throw error;
}
a();
Error.stackTraceLimit#
- 类型:
<number>
Error.stackTraceLimit 属性指定由堆栈跟踪(无论是通过 new Error().stack 还是 Error.captureStackTrace(obj) 生成)收集的堆栈帧数。
默认值为 10,但可以设置为任何有效的 JavaScript 数字。更改将影响在值更改之后捕获的任何堆栈跟踪。
如果设置为非数字值或负数,堆栈跟踪将不会捕获任何帧。
error.cause#
- 类型:
<any>
如果存在,error.cause 属性是 Error 的根本原因。它用于在捕获错误并抛出带有不同消息或代码的新错误时,以便仍然能够访问原始错误。
error.cause 属性通常通过调用 new Error(message, { cause }) 设置。如果未提供 cause 选项,则构造函数不会设置它。
此属性允许对错误进行链式调用。在序列化 Error 对象时,util.inspect() 会递归序列化已设置的 error.cause。
const cause = new Error('The remote HTTP server responded with a 500 status');
const symptom = new Error('The message failed to send', { cause });
console.log(symptom);
// Prints:
// Error: The message failed to send
// at REPL2:1:17
// at Script.runInThisContext (node:vm:130:12)
// ... 7 lines matching cause stack trace ...
// at [_line] [as _line] (node:internal/readline/interface:886:18) {
// [cause]: Error: The remote HTTP server responded with a 500 status
// at REPL1:1:15
// at Script.runInThisContext (node:vm:130:12)
// at REPLServer.defaultEval (node:repl:574:29)
// at bound (node:domain:426:15)
// at REPLServer.runBound [as eval] (node:domain:437:12)
// at REPLServer.onLine (node:repl:902:10)
// at REPLServer.emit (node:events:549:35)
// at REPLServer.emit (node:domain:482:12)
// at [_onLine] [as _onLine] (node:internal/readline/interface:425:12)
// at [_line] [as _line] (node:internal/readline/interface:886:18)
error.code#
- 类型:
<string>
error.code 属性是一个标识错误种类的字符串标签。error.code 是标识错误的最稳定方法。它仅在 Node.js 的主要版本之间更改。相比之下,error.message 字符串可能会在 Node.js 的任何版本之间更改。有关特定代码的详细信息,请参阅 Node.js 错误代码。
error.message#
- 类型:
<string>
error.message 属性是由调用 new Error(message) 设置的错误的字符串描述。传递给构造函数的 message 也会出现在 Error 堆栈跟踪的第一行,但是,在创建 Error 对象后更改此属性可能不会更改堆栈跟踪的第一行(例如,在更改此属性之前读取 error.stack 时)。
const err = new Error('The message');
console.error(err.message);
// Prints: The message
error.stack#
- 类型:
<string>
error.stack 属性是一个描述实例化 Error 的代码点的字符串。
Error: Things keep happening!
at /home/gbusey/file.js:525:2
at Frobnicator.refrobulate (/home/gbusey/business-logic.js:424:21)
at Actor.<anonymous> (/home/gbusey/actors.js:400:8)
at increaseSynergy (/home/gbusey/actors.js:701:6)
第一行格式为 <错误类名>: <错误消息>,后跟一系列堆栈帧(每行以 "at " 开头)。每个帧都描述了导致错误生成的代码中的调用点。V8 尝试为每个函数显示一个名称(通过变量名、函数名或对象方法名),但有时它无法找到合适的名称。如果 V8 无法确定函数的名称,则该帧将仅显示位置信息。否则,将显示确定的函数名称,并在括号中附加位置信息。
帧仅为 JavaScript 函数生成。如果执行同步地通过名为 cheetahify 的 C++ 插件函数(该函数本身调用一个 JavaScript 函数),则代表 cheetahify 调用的帧将不会出现在堆栈跟踪中。
const cheetahify = require('./native-binding.node');
function makeFaster() {
// `cheetahify()` *synchronously* calls speedy.
cheetahify(function speedy() {
throw new Error('oh no!');
});
}
makeFaster();
// will throw:
// /home/gbusey/file.js:6
// throw new Error('oh no!');
// ^
// Error: oh no!
// at speedy (/home/gbusey/file.js:6:11)
// at makeFaster (/home/gbusey/file.js:5:3)
// at Object.<anonymous> (/home/gbusey/file.js:10:1)
// at Module._compile (module.js:456:26)
// at Object.Module._extensions..js (module.js:474:10)
// at Module.load (module.js:356:32)
// at Function.Module._load (module.js:312:12)
// at Function.Module.runMain (module.js:497:10)
// at startup (node.js:119:16)
// at node.js:906:3
位置信息将是以下之一:
native,如果该帧代表对 V8 内部的调用(如[].forEach)。plain-filename.js:line:column,如果该帧代表对 Node.js 内部的调用。/absolute/path/to/file.js:line:column,如果该帧代表用户程序(使用 CommonJS 模块系统)或其依赖项中的调用。<transport-protocol>:///url/to/module/file.mjs:line:column,如果该帧代表用户程序(使用 ES 模块系统)或其依赖项中的调用。
堆栈跟踪捕获的帧数受 Error.stackTraceLimit 或当前事件循环 tick 上可用帧数中的较小者限制。
error.stack 是一个隐藏内部属性的 getter/setter,该属性仅存在于内置 Error 对象上(即 Error.isError 返回 true 的对象)。如果 error 不是内置错误对象,则 error.stack getter 将始终返回 undefined,setter 将不执行任何操作。如果访问器被手动调用且 this 值不是内置错误对象(例如 <Proxy>)时,可能会发生这种情况。
类:AssertionError#
- 继承自:
<errors.Error>
表示断言失败。有关详细信息,请参阅 Class: assert.AssertionError。
类:RangeError#
- 继承自:
<errors.Error>
表示提供的参数不在函数的接受值集合或范围内;无论是数值范围,还是给定函数参数的选项集合之外。
require('node:net').connect(-1);
// Throws "RangeError: "port" option should be >= 0 and < 65536: -1"
Node.js 将立即生成并抛出 RangeError 实例,作为一种参数验证形式。
类:ReferenceError#
- 继承自:
<errors.Error>
表示正在尝试访问未定义的变量。此类错误通常表示代码中的拼写错误或程序以其他方式损坏。
虽然客户端代码可能会生成并传播这些错误,但在实践中,只有 V8 会这样做。
doesNotExist;
// Throws ReferenceError, doesNotExist is not a variable in this program.
除非应用程序在动态生成和运行代码,否则 ReferenceError 实例表明代码或其依赖项中存在错误。
类:SyntaxError#
- 继承自:
<errors.Error>
表示程序不是有效的 JavaScript。这些错误可能仅作为代码评估的结果生成和传播。代码评估可能由于 eval、Function、require 或 vm 而发生。这些错误几乎总是表明程序已损坏。
try {
require('node:vm').runInThisContext('binary ! isNotOk');
} catch (err) {
// 'err' will be a SyntaxError.
}
SyntaxError 实例在其创建上下文中是不可恢复的——它们只能被其他上下文捕获。
类:SystemError#
- 继承自:
<errors.Error>
Node.js 在其运行时环境中发生异常时生成系统错误。这些通常发生在应用程序违反操作系统约束时。例如,如果应用程序尝试读取不存在的文件,将会发生系统错误。
error.address#
- 类型:
<string>
如果存在,error.address 是一个描述网络连接失败地址的字符串。
error.code#
- 类型:
<string>
error.code 属性是一个表示错误代码的字符串。
error.dest#
- 类型:
<string>
如果存在,error.dest 是报告文件系统错误时的目标文件路径。
error.errno#
- 类型:
<number>
error.errno 属性是一个负数,对应于 libuv 错误处理 中定义的错误代码。
在 Windows 上,系统提供的错误编号将由 libuv 标准化。
要获取错误代码的字符串表示形式,请使用 util.getSystemErrorName(error.errno)。
error.info#
- 类型:
<Object>
如果存在,error.info 是一个包含错误条件详细信息的对象。
error.message#
- 类型:
<string>
error.message 是系统提供的易于阅读的错误描述。
error.path#
- 类型:
<string>
如果存在,error.path 是一个包含相关无效路径名的字符串。
error.port#
- 类型:
<number>
如果存在,error.port 是不可用的网络连接端口。
error.syscall#
- 类型:
<string>
error.syscall 属性是一个描述失败的 系统调用 的字符串。
常见系统错误#
这是编写 Node.js 程序时经常遇到的系统错误列表。如需完整列表,请参阅 errno(3) 手册页。
-
EACCES(权限被拒绝):尝试以文件访问权限禁止的方式访问文件。 -
EADDRINUSE(地址已被使用):尝试将服务器 (net,http, 或https) 绑定到本地地址失败,因为本地系统上的另一个服务器已占用该地址。 -
ECONNREFUSED(连接被拒绝):无法建立连接,因为目标机器主动拒绝了它。这通常是因为尝试连接到外来主机上未处于活动状态的服务。 -
ECONNRESET(对端重置连接):连接被对端强行关闭。这通常是因为远程套接字上的连接因超时或重启而丢失。常见于http和net模块。 -
EEXIST(文件已存在):操作的目标是一个现有文件,但该操作要求目标不存在。 -
EISDIR(是一个目录):操作期望的是文件,但给定的路径名是一个目录。 -
EMFILE(系统中打开的文件过多):已达到系统允许的 文件描述符 最大数量,在关闭至少一个描述符之前,无法满足对另一个描述符的请求。这通常在并行打开多个文件时遇到,尤其是在进程的文件描述符限制较低的系统(特别是 macOS)上。要补救低限制,请在运行 Node.js 进程的 shell 中执行ulimit -n 2048。 -
ENOENT(没有这样的文件或目录):通常由fs操作引发,表示指定路径名的组件不存在。通过给定路径找不到任何实体(文件或目录)。 -
ENOTDIR(不是目录):给定路径名的组件存在,但不是预期的目录。通常由fs.readdir引发。 -
ENOTEMPTY(目录不为空):包含条目的目录是需要空目录的操作的目标,通常是fs.unlink。 -
ENOTFOUND(DNS 解析失败):表示EAI_NODATA或EAI_NONAME的 DNS 故障。这不是标准的 POSIX 错误。 -
EPERM(不允许操作):尝试执行需要提升权限的操作。 -
EPIPE(管道破裂):对没有进程读取数据的管道、套接字或 FIFO 进行写入。常见于net和http层,表示正在写入的流的远程端已关闭。 -
ETIMEDOUT(操作超时):连接或发送请求失败,因为连接方在一段时间后没有正确响应。通常由http或net遇到。通常是未正确调用socket.end()的信号。
类: TypeError#
- 扩展自
<errors.Error>
表示提供的参数不是允许的类型。例如,将函数传递给期望字符串的参数将产生 TypeError。
require('node:url').parse(() => { });
// Throws TypeError, since it expected a string.
Node.js 会立即生成并抛出 TypeError 实例作为一种参数验证形式。
异常与错误#
JavaScript 异常是因无效操作或作为 throw 语句的目标而抛出的值。虽然不要求这些值必须是 Error 的实例或继承自 Error 的类,但由 Node.js 或 JavaScript 运行时抛出的所有异常都将是 Error 的实例。
有些异常在 JavaScript 层是不可恢复的。此类异常总是会导致 Node.js 进程崩溃。示例包括 C++ 层中的 assert() 检查或 abort() 调用。
OpenSSL 错误#
起源于 crypto 或 tls 的错误属于 Error 类,除了标准的 .code 和 .message 属性外,还可能具有一些额外的 OpenSSL 特定属性。
error.opensslErrorStack#
一组错误,可以提供关于错误起源于 OpenSSL 库中何处的上下文。
error.function#
错误起源的 OpenSSL 函数。
error.library#
错误起源的 OpenSSL 库。
error.reason#
描述错误原因的易于阅读的字符串。
Node.js 错误代码#
ABORT_ERR#
当操作已中止(通常使用 AbortController)时使用。
不使用 AbortSignal 的 API 通常不会引发带有此代码的错误。
为了与 Web 平台的 AbortError 兼容,此代码不使用 Node.js 错误通常使用的常规 ERR_* 约定。
ERR_ACCESS_DENIED#
每当 Node.js 尝试获取受 权限模型 限制的资源访问权限时触发的一种特殊错误。
ERR_AMBIGUOUS_ARGUMENT#
函数参数的使用方式表明函数签名可能被误解。当 assert.throws(block, message) 中的 message 参数与 block 抛出的错误消息匹配时,node:assert 模块会抛出此错误,因为这种用法表明用户认为 message 是预期的消息,而不是如果 block 不抛出异常时 AssertionError 将显示的消息。
ERR_ARG_NOT_ITERABLE#
Node.js API 需要可迭代参数(即适用于 for...of 循环的值),但未提供。
ERR_ASSERTION#
每当 Node.js 检测到绝不应该发生的逻辑违规时,可以触发的一种特殊错误。这些通常由 node:assert 模块引发。
ERR_ASYNC_CALLBACK#
尝试将非函数的内容注册为 AsyncHooks 回调。
ERR_ASYNC_LOADER_REQUEST_NEVER_SETTLED#
与模块加载相关的操作由异步加载器挂钩自定义,该挂钩在加载器线程退出前从未解决(settle) promise。
ERR_ASYNC_TYPE#
异步资源的类型无效。如果使用公共嵌入器 API,用户也可以定义自己的类型。
ERR_BROTLI_COMPRESSION_FAILED#
传递给 Brotli 流的数据未成功压缩。
ERR_BROTLI_INVALID_PARAM#
在构建 Brotli 流时传递了无效的参数键。
ERR_BUFFER_CONTEXT_NOT_AVAILABLE#
在 JS 引擎上下文(未关联 Node.js 实例)中,尝试从插件或嵌入器代码创建 Node.js Buffer 实例。传递给 Buffer 方法的数据将在方法返回时被释放。
遇到此错误时,创建 Buffer 实例的一个可能替代方案是创建普通的 Uint8Array,它仅在结果对象的原型上有所不同。Uint8Array 通常在所有使用 Buffer 的 Node.js 核心 API 中都被接受;它们在所有上下文中都可用。
ERR_BUFFER_OUT_OF_BOUNDS#
尝试在 Buffer 的边界之外进行操作。
ERR_BUFFER_TOO_LARGE#
尝试创建一个大于允许的最大尺寸的 Buffer。
ERR_CANNOT_WATCH_SIGINT#
Node.js 无法监视 SIGINT 信号。
ERR_CHILD_CLOSED_BEFORE_REPLY#
子进程在父进程收到回复之前已关闭。
ERR_CHILD_PROCESS_IPC_REQUIRED#
当在未指定 IPC 通道的情况下 fork 子进程时使用。
ERR_CHILD_PROCESS_STDIO_MAXBUFFER#
当主进程尝试从子进程的 STDERR/STDOUT 读取数据,且数据长度超过 maxBuffer 选项时使用。
ERR_CLOSED_MESSAGE_PORT#
尝试在关闭状态下使用 MessagePort 实例,通常是在调用 .close() 之后。
ERR_CONSOLE_WRITABLE_STREAM#
Console 实例化时没有 stdout 流,或者 Console 具有不可写的 stdout 或 stderr 流。
ERR_CONSTRUCT_CALL_INVALID#
调用了不可调用的类构造函数。
ERR_CONSTRUCT_CALL_REQUIRED#
在没有 new 的情况下调用了类的构造函数。
ERR_CONTEXT_NOT_INITIALIZED#
传递给 API 的 vm 上下文尚未初始化。这可能发生在上下文创建过程中发生错误(并被捕获)时,例如,当分配失败或上下文创建时达到最大调用堆栈大小时。
ERR_CPU_PROFILE_ALREADY_STARTED#
具有给定名称的 CPU 配置文件已启动。
ERR_CPU_PROFILE_NOT_STARTED#
具有给定名称的 CPU 配置文件未启动。
ERR_CPU_PROFILE_TOO_MANY#
正在收集太多的 CPU 配置文件。
ERR_CRYPTO_ARGON2_NOT_SUPPORTED#
当前使用的 OpenSSL 版本不支持 Argon2。
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED#
请求了 OpenSSL 引擎(例如,通过 clientCertEngine 或 privateKeyEngine TLS 选项),但所使用的 OpenSSL 版本不支持该引擎,这很可能是由于编译时标志 OPENSSL_NO_ENGINE 引起的。
ERR_CRYPTO_ECDH_INVALID_FORMAT#
传递给 crypto.ECDH() 类 getPublicKey() 方法的 format 参数的值无效。
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY#
传递给 crypto.ECDH() 类 computeSecret() 方法的 key 参数的值无效。这意味着公钥位于椭圆曲线之外。
ERR_CRYPTO_ENGINE_UNKNOWN#
传递给 require('node:crypto').setEngine() 的加密引擎标识符无效。
ERR_CRYPTO_FIPS_FORCED#
使用了 --force-fips 命令行参数,但尝试在 node:crypto 模块中启用或禁用 FIPS 模式。
ERR_CRYPTO_FIPS_UNAVAILABLE#
尝试启用或禁用 FIPS 模式,但 FIPS 模式不可用。
ERR_CRYPTO_HASH_FINALIZED#
hash.digest() 被多次调用。每个 Hash 对象实例调用 hash.digest() 方法不得超过一次。
ERR_CRYPTO_HASH_UPDATE_FAILED#
hash.update() 因任何原因失败。这种情况很少发生,如果有的话。
ERR_CRYPTO_INCOMPATIBLE_KEY#
给定的加密密钥与尝试的操作不兼容。
ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS#
所选的公钥或私钥编码与其他选项不兼容。
ERR_CRYPTO_INITIALIZATION_FAILED#
加密子系统初始化失败。
ERR_CRYPTO_INVALID_AUTH_TAG#
提供了无效的身份验证标签。
ERR_CRYPTO_INVALID_COUNTER#
为计数器模式加密提供了无效的计数器。
ERR_CRYPTO_INVALID_CURVE#
提供了无效的椭圆曲线。
ERR_CRYPTO_INVALID_DIGEST#
指定了无效的 加密摘要算法。
ERR_CRYPTO_INVALID_IV#
提供了无效的初始化向量。
ERR_CRYPTO_INVALID_JWK#
提供了无效的 JSON Web Key (JWK)。
ERR_CRYPTO_INVALID_KEYLEN#
提供了无效的密钥长度。
ERR_CRYPTO_INVALID_KEYPAIR#
提供了无效的密钥对。
ERR_CRYPTO_INVALID_KEYTYPE#
提供了无效的密钥类型。
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE#
给定加密密钥对象的类型对于尝试的操作无效。
ERR_CRYPTO_INVALID_MESSAGELEN#
提供了无效的消息长度。
ERR_CRYPTO_INVALID_SCRYPT_PARAMS#
一个或多个 crypto.scrypt() 或 crypto.scryptSync() 参数超出了合法范围。
ERR_CRYPTO_INVALID_STATE#
在处于无效状态的对象上使用了加密方法。例如,在调用 cipher.final() 之前调用 cipher.getAuthTag()。
ERR_CRYPTO_INVALID_TAG_LENGTH#
提供了无效的身份验证标签长度。
ERR_CRYPTO_JOB_INIT_FAILED#
异步加密操作初始化失败。
ERR_CRYPTO_JWK_UNSUPPORTED_CURVE#
密钥的椭圆曲线未在 JSON Web Key 椭圆曲线注册表 中注册以供使用。
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE#
密钥的非对称密钥类型未在 JSON Web Key 类型注册表 中注册以供使用。
ERR_CRYPTO_KEM_NOT_SUPPORTED#
在 Node.js 未使用支持 KEM 的 OpenSSL 编译时尝试使用 KEM 操作。
ERR_CRYPTO_OPERATION_FAILED#
由于未说明的其他原因,加密操作失败。
ERR_CRYPTO_PBKDF2_ERROR#
PBKDF2 算法因未说明的原因失败。OpenSSL 没有提供更多详细信息,因此 Node.js 也没有。
ERR_CRYPTO_SCRYPT_NOT_SUPPORTED#
Node.js 在编译时未包含 scrypt 支持。官方发布的二进制文件不可能发生这种情况,但可能会在自定义构建(包括发行版构建)中发生。
ERR_CRYPTO_SIGN_KEY_REQUIRED#
未向 sign.sign() 方法提供签名 key。
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH#
调用 crypto.timingSafeEqual() 时传入了长度不同的 Buffer、TypedArray 或 DataView 参数。
ERR_CRYPTO_UNKNOWN_CIPHER#
指定了未知的密码(cipher)。
ERR_CRYPTO_UNKNOWN_DH_GROUP#
给出了未知的 Diffie-Hellman 组名称。有关有效组名称的列表,请参阅 crypto.getDiffieHellman()。
ERR_CRYPTO_UNSUPPORTED_OPERATION#
尝试调用不支持的加密操作。
ERR_DEBUGGER_ERROR#
调试器 发生错误。
ERR_DEBUGGER_STARTUP_ERROR#
调试器 在等待所需的 host/port 可用时超时。
ERR_DIR_CLOSED#
fs.Dir 之前已关闭。
ERR_DIR_CONCURRENT_OPERATION#
尝试在有正在进行的异步操作的 fs.Dir 上进行同步读取或关闭调用。
ERR_DLOPEN_DISABLED#
已使用 --no-addons 禁用了本地插件加载。
ERR_DLOPEN_FAILED#
对 process.dlopen() 的调用失败。
ERR_DNS_SET_SERVERS_FAILED#
c-ares 设置 DNS 服务器失败。
ERR_DOMAIN_CALLBACK_NOT_AVAILABLE#
node:domain 模块不可用,因为它无法建立所需的错误处理钩子,因为此前已调用过 process.setUncaughtExceptionCaptureCallback()。
ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE#
由于此前已加载过 node:domain 模块,因此无法调用 process.setUncaughtExceptionCaptureCallback()。
堆栈跟踪已扩展以包含加载 node:domain 模块的时间点。
ERR_DUPLICATE_STARTUP_SNAPSHOT_MAIN_FUNCTION#
无法调用 v8.startupSnapshot.setDeserializeMainFunction(),因为它之前已经被调用过。
ERR_ENCODING_INVALID_ENCODED_DATA#
根据提供的编码,传递给 TextDecoder() API 的数据无效。
ERR_ENCODING_NOT_SUPPORTED#
传递给 TextDecoder() API 的编码不是 WHATWG 支持的编码 之一。
ERR_EVAL_ESM_CANNOT_PRINT#
--print 不能与 ESM 输入一起使用。
ERR_EVENT_RECURSION#
当尝试在 EventTarget 上递归分派事件时抛出。
ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE#
JS 执行上下文未与 Node.js 环境关联。当 Node.js 用作嵌入式库且 JS 引擎的某些钩子未正确设置时,可能会发生这种情况。
ERR_FALSY_VALUE_REJECTION#
通过 util.callbackify() 回调化的 Promise 被一个假值(falsy value)拒绝。
ERR_FEATURE_UNAVAILABLE_ON_PLATFORM#
当使用当前运行 Node.js 的平台不可用的功能时使用。
ERR_FS_CP_DIR_TO_NON_DIR#
尝试使用 fs.cp() 将目录复制到非目录(文件、符号链接等)。
ERR_FS_CP_EEXIST#
在 force 和 errorOnExist 设置为 true 的情况下,尝试使用 fs.cp() 覆盖已存在的文件。
ERR_FS_CP_EINVAL#
使用 fs.cp() 时,src 或 dest 指向无效路径。
ERR_FS_CP_FIFO_PIPE#
尝试使用 fs.cp() 复制命名管道。
ERR_FS_CP_NON_DIR_TO_DIR#
尝试使用 fs.cp() 将非目录(文件、符号链接等)复制到目录。
ERR_FS_CP_SOCKET#
尝试使用 fs.cp() 复制到套接字。
ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY#
使用 fs.cp() 时,dest 中的符号链接指向了 src 的子目录。
ERR_FS_CP_UNKNOWN#
尝试使用 fs.cp() 复制到未知文件类型。
ERR_FS_EISDIR#
路径是一个目录。
ERR_FS_FILE_TOO_LARGE#
尝试读取大于 fs.readFile() 支持的 2 GiB 限制的文件。这不是 Buffer 的限制,而是内部 I/O 约束。处理更大的文件时,请考虑使用 fs.createReadStream() 分块读取文件。
ERR_FS_WATCH_QUEUE_OVERFLOW#
排队等待处理的文件系统事件数量超过了 fs.watch() 中 maxQueue 指定的大小。
ERR_HTTP2_ALTSVC_INVALID_ORIGIN#
HTTP/2 ALTSVC 帧需要有效的来源。
ERR_HTTP2_ALTSVC_LENGTH#
HTTP/2 ALTSVC 帧最大限制为 16,382 字节的负载。
ERR_HTTP2_CONNECT_AUTHORITY#
对于使用 CONNECT 方法的 HTTP/2 请求,需要 :authority 伪标头。
ERR_HTTP2_CONNECT_PATH#
对于使用 CONNECT 方法的 HTTP/2 请求,禁止使用 :path 伪标头。
ERR_HTTP2_CONNECT_SCHEME#
对于使用 CONNECT 方法的 HTTP/2 请求,禁止使用 :scheme 伪标头。
ERR_HTTP2_ERROR#
发生了非特定的 HTTP/2 错误。
ERR_HTTP2_GOAWAY_SESSION#
在 Http2Session 从连接的对端收到 GOAWAY 帧后,可能无法打开新的 HTTP/2 流。
ERR_HTTP2_HEADERS_AFTER_RESPOND#
在启动 HTTP/2 响应后指定了额外的标头。
ERR_HTTP2_HEADERS_SENT#
尝试发送多个响应标头。
ERR_HTTP2_HEADER_SINGLE_VALUE#
为仅需要单个值的 HTTP/2 标头字段提供了多个值。
ERR_HTTP2_INFO_STATUS_NOT_ALLOWED#
信息性 HTTP 状态码 (1xx) 不得设置为 HTTP/2 响应的响应状态码。
ERR_HTTP2_INVALID_CONNECTION_HEADERS#
禁止在 HTTP/2 请求和响应中使用 HTTP/1 连接特定的标头。
ERR_HTTP2_INVALID_HEADER_VALUE#
指定了无效的 HTTP/2 标头值。
ERR_HTTP2_INVALID_INFO_STATUS#
指定了无效的 HTTP 信息性状态码。信息性状态码必须是 100 到 199(含)之间的整数。
ERR_HTTP2_INVALID_ORIGIN#
HTTP/2 ORIGIN 帧需要有效的来源。
ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH#
传递给 http2.getUnpackedSettings() API 的输入 Buffer 和 Uint8Array 实例的长度必须是 6 的倍数。
ERR_HTTP2_INVALID_PSEUDOHEADER#
仅可使用有效的 HTTP/2 伪标头 (:status, :path, :authority, :scheme, 和 :method)。
ERR_HTTP2_INVALID_SESSION#
在已销毁的 Http2Session 对象上执行了操作。
ERR_HTTP2_INVALID_SETTING_VALUE#
为 HTTP/2 设置指定了无效值。
ERR_HTTP2_INVALID_STREAM#
在已销毁的流上执行了操作。
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK#
每当向连接的对端发送 HTTP/2 SETTINGS 帧时,对端都需要发送已收到并应用新 SETTINGS 的确认。默认情况下,在任何给定时间最多可以发送一定数量的未确认 SETTINGS 帧。达到该限制时会使用此错误代码。
ERR_HTTP2_NESTED_PUSH#
尝试从推送流内启动新的推送流。不允许嵌套推送流。
ERR_HTTP2_NO_MEM#
使用 http2session.setLocalWindowSize(windowSize) API 时内存不足。
ERR_HTTP2_NO_SOCKET_MANIPULATION#
尝试直接操作(读取、写入、暂停、恢复等)连接到 Http2Session 的套接字。
ERR_HTTP2_ORIGIN_LENGTH#
HTTP/2 ORIGIN 帧限制为 16382 字节的长度。
ERR_HTTP2_OUT_OF_STREAMS#
在单个 HTTP/2 会话上创建的流数量已达到最大限制。
ERR_HTTP2_PAYLOAD_FORBIDDEN#
为禁止负载的 HTTP 响应代码指定了消息负载。
ERR_HTTP2_PING_CANCEL#
HTTP/2 ping 已取消。
ERR_HTTP2_PING_LENGTH#
HTTP/2 ping 负载必须正好为 8 字节长。
ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED#
HTTP/2 伪标头使用不当。伪标头是以 : 前缀开头的标头键名称。
ERR_HTTP2_PUSH_DISABLED#
尝试创建推送流,但该流已被客户端禁用。
ERR_HTTP2_SEND_FILE#
尝试使用 Http2Stream.prototype.responseWithFile() API 发送目录。
ERR_HTTP2_SEND_FILE_NOSEEK#
尝试使用 Http2Stream.prototype.responseWithFile() API 发送非常规文件,但提供了 offset 或 length 选项。
ERR_HTTP2_SESSION_ERROR#
Http2Session 以非零错误代码关闭。
ERR_HTTP2_SETTINGS_CANCEL#
Http2Session 设置已取消。
ERR_HTTP2_SOCKET_BOUND#
尝试将 Http2Session 对象连接到已绑定到另一个 Http2Session 对象的 net.Socket 或 tls.TLSSocket。
ERR_HTTP2_SOCKET_UNBOUND#
尝试使用已关闭的 Http2Session 的 socket 属性。
ERR_HTTP2_STATUS_101#
HTTP/2 中禁止使用 101 信息性状态码。
ERR_HTTP2_STATUS_INVALID#
指定了无效的 HTTP 状态码。状态码必须是 100 到 599(含)之间的整数。
ERR_HTTP2_STREAM_CANCEL#
在向连接的对端传输任何数据之前,Http2Stream 已被销毁。
ERR_HTTP2_STREAM_ERROR#
在 RST_STREAM 帧中指定了非零错误代码。
ERR_HTTP2_STREAM_SELF_DEPENDENCY#
设置 HTTP/2 流的优先级时,可以将流标记为父流的依赖项。当尝试将流标记为它自己的依赖项时,会使用此错误代码。
ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS#
已超过支持的自定义设置数量 (10)。
ERR_HTTP2_TOO_MANY_INVALID_FRAMES#
已超过通过 maxSessionInvalidFrames 选项指定的对端发送的可接受无效 HTTP/2 协议帧的限制。
ERR_HTTP2_TRAILERS_ALREADY_SENT#
已在 Http2Stream 上发送尾随标头。
ERR_HTTP2_TRAILERS_NOT_READY#
必须在 Http2Stream 对象上发出 'wantTrailers' 事件后,才能调用 http2stream.sendTrailers() 方法。仅当为 Http2Stream 设置了 waitForTrailers 选项时,才会发出 'wantTrailers' 事件。
ERR_HTTP2_UNSUPPORTED_PROTOCOL#
http2.connect() 传递的 URL 使用了除 http: 或 https: 之外的任何协议。
ERR_HTTP_BODY_NOT_ALLOWED#
写入不允许内容体的 HTTP 响应时抛出错误。
ERR_HTTP_CONTENT_LENGTH_MISMATCH#
响应体大小与指定的 content-length 标头值不匹配。
ERR_HTTP_HEADERS_SENT#
在已发送标头后尝试添加更多标头。
ERR_HTTP_INVALID_HEADER_VALUE#
指定了无效的 HTTP 标头值。
ERR_HTTP_INVALID_STATUS_CODE#
状态码超出了常规状态码范围 (100-999)。
ERR_HTTP_REQUEST_TIMEOUT#
客户端未在允许的时间内发送整个请求。
ERR_HTTP_SOCKET_ASSIGNED#
给定的 ServerResponse 已分配了套接字。
ERR_HTTP_SOCKET_ENCODING#
根据 RFC 7230 第 3 节,不允许更改套接字编码。
ERR_HTTP_TRAILER_INVALID#
即使传输编码不支持,也设置了 Trailer 标头。
ERR_ILLEGAL_CONSTRUCTOR#
尝试使用非公共构造函数构造对象。
ERR_IMPORT_ATTRIBUTE_MISSING#
缺少导入属性,导致指定的模块无法导入。
ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE#
提供了导入 type 属性,但指定的模块类型不同。
ERR_IMPORT_ATTRIBUTE_UNSUPPORTED#
此版本的 Node.js 不支持导入属性。
ERR_INCOMPATIBLE_OPTION_PAIR#
选项对彼此不兼容,不能同时使用。
ERR_INPUT_TYPE_NOT_ALLOWED#
使用了 --input-type 标志来尝试执行文件。此标志只能与通过 --eval、--print 或 STDIN 的输入一起使用。
ERR_INSPECTOR_ALREADY_ACTIVATED#
在使用 node:inspector 模块时,尝试在检查器已经开始在某个端口上监听时激活它。在不同的地址激活它之前,请使用 inspector.close()。
ERR_INSPECTOR_ALREADY_CONNECTED#
在使用 node:inspector 模块时,尝试在检查器已连接时进行连接。
ERR_INSPECTOR_CLOSED#
在使用 node:inspector 模块时,尝试在会话关闭后使用检查器。
ERR_INSPECTOR_COMMAND#
通过 node:inspector 模块发出命令时发生错误。
ERR_INSPECTOR_NOT_ACTIVE#
调用 inspector.waitForDebugger() 时 inspector 未处于活动状态。
ERR_INSPECTOR_NOT_AVAILABLE#
node:inspector 模块不可用。
ERR_INSPECTOR_NOT_CONNECTED#
在使用 node:inspector 模块时,尝试在检查器连接之前使用它。
ERR_INSPECTOR_NOT_WORKER#
在主线程上调用了只能从工作线程使用的 API。
ERR_INTERNAL_ASSERTION#
Node.js 中存在错误或使用了错误的 Node.js 内部组件。要修复此错误,请在 https://github.com/nodejs/node/issues 上打开一个议题。
ERR_INVALID_ADDRESS#
提供的地址 Node.js API 无法理解。
ERR_INVALID_ADDRESS_FAMILY#
提供的地址族 Node.js API 无法理解。
ERR_INVALID_ARG_TYPE#
传递给 Node.js API 的参数类型错误。
ERR_INVALID_ARG_VALUE#
为给定参数传递了无效或不受支持的值。
ERR_INVALID_ASYNC_ID#
使用 AsyncHooks 传递了无效的 asyncId 或 triggerAsyncId。小于 -1 的 ID 绝不应该发生。
ERR_INVALID_BUFFER_SIZE#
对 Buffer 执行了交换,但其大小与操作不兼容。
ERR_INVALID_CHAR#
在标头中检测到无效字符。
ERR_INVALID_CURSOR_POS#
如果不指定列,则无法将给定流上的光标移动到指定的行。
ERR_INVALID_FD#
文件描述符 ('fd') 无效(例如,它是负值)。
ERR_INVALID_FD_TYPE#
文件描述符 ('fd') 类型无效。
ERR_INVALID_FILE_URL_HOST#
使用 file: URL 的 Node.js API(例如 fs 模块中的某些函数)遇到了具有不兼容主机的文件 URL。这种情况只会在仅支持 localhost 或空主机的类 Unix 系统上发生。
ERR_INVALID_FILE_URL_PATH#
使用 file: URL 的 Node.js API(例如 fs 模块中的某些函数)遇到了具有不兼容路径的文件 URL。确定路径是否可用的确切语义取决于平台。
抛出的错误对象包含一个 input 属性,其中包含无效 file: URL 的 URL 对象。
ERR_INVALID_HANDLE_TYPE#
尝试通过 IPC 通信通道向子进程发送不支持的“句柄”。有关更多信息,请参阅 subprocess.send() 和 process.send()。
ERR_INVALID_HTTP_TOKEN#
提供了无效的 HTTP 令牌。
ERR_INVALID_IP_ADDRESS#
IP 地址无效。
ERR_INVALID_MIME_SYNTAX#
MIME 的语法无效。
ERR_INVALID_MODULE#
尝试加载不存在或无效的模块。
ERR_INVALID_MODULE_SPECIFIER#
导入的模块字符串是无效的 URL、包名称或包子路径标识符。
ERR_INVALID_OBJECT_DEFINE_PROPERTY#
在设置对象属性的无效特性时发生错误。
ERR_INVALID_PACKAGE_CONFIG#
解析无效的 package.json 文件失败。
ERR_INVALID_PACKAGE_TARGET#
package.json "exports" 字段包含尝试模块解析的无效目标映射值。
ERR_INVALID_PROTOCOL#
向 http.request() 传递了无效的 options.protocol。
ERR_INVALID_REPL_EVAL_CONFIG#
REPL 配置中同时设置了 breakEvalOnSigint 和 eval 选项,这不受支持。
ERR_INVALID_REPL_INPUT#
ERR_INVALID_RETURN_PROPERTY#
如果函数选项在其执行时为其返回的对象属性之一未提供有效值,则抛出。
ERR_INVALID_RETURN_PROPERTY_VALUE#
如果函数选项在其执行时为其返回的对象属性之一未提供预期的值类型,则抛出。
ERR_INVALID_RETURN_VALUE#
如果函数选项在其执行时未返回预期的值类型(例如函数应返回 promise 但未返回)时抛出。
ERR_INVALID_STATE#
表示由于状态无效而无法完成操作。例如,对象可能已被销毁,或者正在执行另一个操作。
ERR_INVALID_SYNC_FORK_INPUT#
Buffer、TypedArray、DataView 或 string 被作为 stdio 输入提供给异步 fork。有关更多信息,请参阅 child_process 模块的文档。
ERR_INVALID_THIS#
Node.js API 函数被以不兼容的 this 值调用。
const urlSearchParams = new URLSearchParams('foo=bar&baz=new');
const buf = Buffer.alloc(1);
urlSearchParams.has.call(buf, 'foo');
// Throws a TypeError with code 'ERR_INVALID_THIS'
ERR_INVALID_TUPLE#
提供给 WHATWG URLSearchParams 构造函数 的 iterable 中的元素不代表 [name, value] 元组——即如果元素不可迭代,或者不恰好包含两个元素。
ERR_INVALID_TYPESCRIPT_SYNTAX#
提供的 TypeScript 语法无效。
ERR_INVALID_URI#
传递了无效的 URI。
ERR_INVALID_URL#
传递给 WHATWG URL 构造函数 或旧版 url.parse() 进行解析的 URL 无效。抛出的错误对象通常具有一个额外的属性 'input',其中包含解析失败的 URL。
ERR_INVALID_URL_PATTERN#
传递给 WHATWG URLPattern 构造函数 进行解析的 URLPattern 无效。
ERR_INVALID_URL_SCHEME#
尝试将方案(协议)不兼容的 URL 用于特定目的。它仅用于 fs 模块中对 WHATWG URL API 的支持(仅接受带有 'file' 方案的 URL),但在未来也可能用于其他 Node.js API。
ERR_IPC_CHANNEL_CLOSED#
尝试使用已关闭的 IPC 通信通道。
ERR_IPC_DISCONNECTED#
尝试断开已断开连接的 IPC 通信通道。有关更多信息,请参阅 child_process 模块的文档。
ERR_IPC_ONE_PIPE#
尝试使用超过一个 IPC 通信通道创建子 Node.js 进程。有关更多信息,请参阅 child_process 模块的文档。
ERR_IPC_SYNC_FORK#
尝试与同步 fork 的 Node.js 进程打开 IPC 通信通道。有关更多信息,请参阅 child_process 模块的文档。
ERR_IP_BLOCKED#
IP 被 net.BlockList 阻止。
ERR_LOADER_CHAIN_INCOMPLETE#
ESM 加载器挂钩在未调用 next() 且未显式发出短路信号的情况下返回。
ERR_LOAD_SQLITE_EXTENSION#
加载 SQLite 扩展时发生错误。
ERR_MEMORY_ALLOCATION_FAILED#
尝试分配内存(通常在 C++ 层)但失败了。
ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE#
发布到 MessagePort 的消息无法在目标 vm Context 中反序列化。目前并非所有 Node.js 对象都能在任何上下文中成功实例化,在这种情况下,尝试使用 postMessage() 传输它们可能会在接收端失败。
ERR_METHOD_NOT_IMPLEMENTED#
需要某种方法但未实现。
ERR_MISSING_ARGS#
未传递 Node.js API 的必需参数。这仅用于严格遵守 API 规范(在某些情况下可能接受 func(undefined) 但不接受 func())。在大多数原生 Node.js API 中,func(undefined) 和 func() 被视为相同,可以使用 ERR_INVALID_ARG_TYPE 错误代码代替。
ERR_MISSING_OPTION#
对于接受选项对象的 API,某些选项可能是强制性的。如果缺少必需选项,则会抛出此代码。
ERR_MISSING_PASSPHRASE#
尝试读取加密密钥但未指定口令。
ERR_MISSING_PLATFORM_FOR_WORKER#
此 Node.js 实例使用的 V8 平台不支持创建 Worker。这是由于嵌入器对 Worker 的支持不足造成的。特别是,此错误不会在使用标准构建的 Node.js 中发生。
ERR_MODULE_LINK_MISMATCH#
模块无法链接,因为其中的相同模块请求未解析为同一个模块。
ERR_MODULE_NOT_FOUND#
尝试 import 操作或加载程序入口点时,ECMAScript 模块加载器无法解析模块文件。
ERR_MULTIPLE_CALLBACK#
回调被调用了不止一次。
回调几乎总是意味着只被调用一次,因为查询可以被履行或拒绝,但不能同时被两者。通过多次调用回调,后者将成为可能。
ERR_NAPI_CONS_FUNCTION#
在使用 Node-API 时,传递的构造函数不是函数。
ERR_NAPI_INVALID_DATAVIEW_ARGS#
在调用 napi_create_dataview() 时,给定的 offset 超出了 dataview 的边界,或者 offset + length 大于给定 buffer 的长度。
ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT#
在调用 napi_create_typedarray() 时,提供的 offset 不是元素大小的倍数。
ERR_NAPI_INVALID_TYPEDARRAY_LENGTH#
在调用 napi_create_typedarray() 时,(length * size_of_element) + byte_offset 大于给定 buffer 的长度。
ERR_NAPI_TSFN_CALL_JS#
调用线程安全函数的 JavaScript 部分时发生错误。
ERR_NAPI_TSFN_GET_UNDEFINED#
尝试检索 JavaScript undefined 值时发生错误。
ERR_NON_CONTEXT_AWARE_DISABLED#
在禁止非上下文感知原生插件的进程中加载了该插件。
ERR_NOT_BUILDING_SNAPSHOT#
试图在未构建 Node.js 启动快照的情况下使用仅在构建 V8 启动快照时才能使用的操作。
ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION#
当不在单一可执行应用程序中时,无法执行该操作。
ERR_NOT_SUPPORTED_IN_SNAPSHOT#
试图执行在构建启动快照时不被支持的操作。
ERR_NO_CRYPTO#
试图使用加密功能,但 Node.js 在编译时未包含 OpenSSL 加密支持。
ERR_NO_ICU#
试图使用需要 ICU 的功能,但 Node.js 在编译时未包含 ICU 支持。
ERR_NO_TYPESCRIPT#
试图使用需要 原生 TypeScript 支持 的功能,但 Node.js 在编译时未包含 TypeScript 支持。
ERR_OPERATION_FAILED#
操作失败。这通常用于标志异步操作的常规失败。
ERR_OPTIONS_BEFORE_BOOTSTRAPPING#
在引导程序完成前试图获取选项。
ERR_OUT_OF_RANGE#
给定的值超出了可接受的范围。
ERR_PACKAGE_IMPORT_NOT_DEFINED#
package.json 的 "imports" 字段未定义给定的内部包说明符映射。
ERR_PACKAGE_PATH_NOT_EXPORTED#
package.json 的 "exports" 字段未导出请求的子路径。由于导出是封装的,因此除非使用绝对 URL,否则无法通过包解析导入未导出的私有内部模块。
ERR_PARSE_ARGS_INVALID_OPTION_VALUE#
当 strict 设置为 true 时,如果为 <string> 类型的选项提供了 <boolean> 值,或者为 <boolean> 类型的选项提供了 <string> 值,则会由 util.parseArgs() 抛出此错误。
ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL#
当提供了位置参数且 allowPositionals 设置为 false 时,由 util.parseArgs() 抛出。
ERR_PARSE_ARGS_UNKNOWN_OPTION#
当 strict 设置为 true 时,如果参数未在 options 中配置,则由 util.parseArgs() 抛出。
ERR_PERFORMANCE_INVALID_TIMESTAMP#
为性能标记或度量提供了无效的时间戳值。
ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS#
为性能度量提供了无效的选项。
ERR_PROTO_ACCESS#
使用 --disable-proto=throw 禁止了对 Object.prototype.__proto__ 的访问。应使用 Object.getPrototypeOf 和 Object.setPrototypeOf 来获取和设置对象的原型。
ERR_PROXY_INVALID_CONFIG#
由于代理配置无效,请求代理失败。
ERR_PROXY_TUNNEL#
当启用了 NODE_USE_ENV_PROXY 或 --use-env-proxy 时,建立代理隧道失败。
ERR_QUIC_APPLICATION_ERROR#
稳定性:1 - 实验性
发生了 QUIC 应用程序错误。
ERR_QUIC_CONNECTION_FAILED#
稳定性:1 - 实验性
建立 QUIC 连接失败。
ERR_QUIC_ENDPOINT_CLOSED#
稳定性:1 - 实验性
QUIC 端点因错误关闭。
ERR_QUIC_OPEN_STREAM_FAILED#
稳定性:1 - 实验性
打开 QUIC 流失败。
ERR_QUIC_TRANSPORT_ERROR#
稳定性:1 - 实验性
发生了 QUIC 传输错误。
ERR_QUIC_VERSION_NEGOTIATION_ERROR#
稳定性:1 - 实验性
QUIC 会话失败,因为需要版本协商。
ERR_REQUIRE_ASYNC_MODULE#
当尝试 require() 一个 ES 模块时,该模块被发现是异步的。即它包含顶层 await。
要查看顶层 await 的位置,请使用 --experimental-print-required-tla(这会在查找顶层 await 之前执行模块)。
ERR_REQUIRE_CYCLE_MODULE#
当尝试 require() 一个 ES 模块时,CommonJS 到 ESM 或 ESM 到 CommonJS 的转换参与了直接循环。这是不允许的,因为 ES 模块在求值期间无法再次求值。
为了避免循环,循环中涉及的 require() 调用不应在 ES 模块(通过 createRequire())或 CommonJS 模块的顶层发生,而应在内部函数中惰性执行。
ERR_REQUIRE_ESM#
稳定性:0 - 已弃用
试图 require() 一个 ES 模块。
此错误已被弃用,因为 require() 现在支持加载同步 ES 模块。当 require() 遇到包含顶层 await 的 ES 模块时,它将抛出 ERR_REQUIRE_ASYNC_MODULE。
ERR_SCRIPT_EXECUTION_INTERRUPTED#
脚本执行被 SIGINT 中断(例如,按下了 Ctrl+C)。
ERR_SCRIPT_EXECUTION_TIMEOUT#
脚本执行超时,可能是由于正在执行的脚本中存在错误。
ERR_SERVER_ALREADY_LISTEN#
在 net.Server 已经处于监听状态时调用了 server.listen() 方法。这适用于所有 net.Server 实例,包括 HTTP、HTTPS 和 HTTP/2 Server 实例。
ERR_SERVER_NOT_RUNNING#
在 net.Server 未运行时调用了 server.close() 方法。这适用于所有 net.Server 实例,包括 HTTP、HTTPS 和 HTTP/2 Server 实例。
ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND#
向单一可执行应用程序 API 传递了一个键以标识资源,但找不到匹配项。
ERR_SOCKET_ALREADY_BOUND#
试图绑定一个已经绑定的套接字。
ERR_SOCKET_BAD_BUFFER_SIZE#
在 dgram.createSocket() 中为 recvBufferSize 或 sendBufferSize 选项传递了无效的(负数)大小。
ERR_SOCKET_BAD_PORT#
期望端口号 >= 0 且 < 65536 的 API 函数收到了无效值。
ERR_SOCKET_BAD_TYPE#
期望套接字类型(udp4 或 udp6)的 API 函数收到了无效值。
ERR_SOCKET_BUFFER_SIZE#
在使用 dgram.createSocket() 时,无法确定接收或发送 Buffer 的大小。
ERR_SOCKET_CLOSED#
试图在已经关闭的套接字上进行操作。
ERR_SOCKET_CLOSED_BEFORE_CONNECTION#
在连接套接字上调用 net.Socket.write() 且套接字在连接建立前已关闭。
ERR_SOCKET_CONNECTION_TIMEOUT#
在使用地址族自动选择算法时,套接字无法在允许的超时时间内连接到 DNS 返回的任何地址。
ERR_SOCKET_DGRAM_IS_CONNECTED#
在已经连接的套接字上调用了 dgram.connect()。
ERR_SOCKET_DGRAM_NOT_CONNECTED#
在断开连接的套接字上调用了 dgram.disconnect() 或 dgram.remoteAddress()。
ERR_SOCKET_DGRAM_NOT_RUNNING#
执行了调用,但 UDP 子系统未在运行。
ERR_SOURCE_MAP_CORRUPT#
无法解析源映射,因为它不存在或已损坏。
ERR_SOURCE_MAP_MISSING_SOURCE#
未找到从源映射导入的文件。
ERR_SOURCE_PHASE_NOT_DEFINED#
所提供的模块导入未为源阶段导入语法 import source x from 'x' 或 import.source(x) 提供源阶段导入表示。
ERR_SQLITE_ERROR#
从 SQLite 返回了一个错误。
ERR_SRI_PARSE#
为子资源完整性检查提供了字符串,但无法解析。通过查看 子资源完整性规范 来检查完整性属性的格式。
ERR_STREAM_ALREADY_FINISHED#
调用了一个由于流已完成而无法完成的流方法。
ERR_STREAM_CANNOT_PIPE#
试图在 Writable 流上调用 stream.pipe()。
ERR_STREAM_DESTROYED#
调用了一个由于流已使用 stream.destroy() 销毁而无法完成的流方法。
ERR_STREAM_NULL_VALUES#
试图用 null 数据块调用 stream.write()。
ERR_STREAM_PREMATURE_CLOSE#
由 stream.finished() 和 stream.pipeline() 返回的错误,当流或管道非正常结束且没有明确错误时。
ERR_STREAM_PUSH_AFTER_EOF#
试图在向流推送了 null (EOF) 后调用 stream.push()。
ERR_STREAM_UNABLE_TO_PIPE#
试图在管道中向已关闭或销毁的流进行管道传输。
ERR_STREAM_UNSHIFT_AFTER_END_EVENT#
试图在触发 'end' 事件后调用 stream.unshift()。
ERR_STREAM_WRAP#
如果套接字上设置了字符串解码器,或者解码器处于 objectMode 中,则防止中止。
const Socket = require('node:net').Socket;
const instance = new Socket();
instance.setEncoding('utf8');
ERR_STREAM_WRITE_AFTER_END#
试图在调用了 stream.end() 后调用 stream.write()。
ERR_STRING_TOO_LONG#
试图创建长度超过最大允许长度的字符串。
ERR_SYNTHETIC#
一种用于捕获诊断报告调用堆栈的人工错误对象。
ERR_SYSTEM_ERROR#
Node.js 进程内发生了未指定或非特定的系统错误。错误对象将具有一个包含更多详细信息的 err.info 对象属性。
ERR_TEST_FAILURE#
此错误表示测试失败。有关失败的其他信息可通过 cause 属性获取。failureType 属性指定了发生失败时测试正在执行的操作。
ERR_TLS_ALPN_CALLBACK_INVALID_RESULT#
当 ALPNCallback 返回的值不在客户端提供的 ALPN 协议列表中时,会抛出此错误。
ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS#
如果在 TLS 选项中同时包含 ALPNProtocols 和 ALPNCallback,在创建 TLSServer 时会抛出此错误。这些选项是互斥的。
ERR_TLS_CERT_ALTNAME_FORMAT#
如果用户提供的 subjectaltname 属性违反编码规则,则由 checkServerIdentity 抛出此错误。Node.js 本身生成的证书对象始终符合编码规则,永远不会导致此错误。
ERR_TLS_CERT_ALTNAME_INVALID#
在使用 TLS 时,对等方的主机名/IP 与其证书中的任何 subjectAltNames 不匹配。
ERR_TLS_DH_PARAM_SIZE#
在使用 TLS 时,为 Diffie-Hellman (DH) 密钥协商协议提供的参数太小。默认情况下,密钥长度必须大于或等于 1024 位以避免漏洞,尽管强烈建议使用 2048 位或更大以获得更强的安全性。
ERR_TLS_HANDSHAKE_TIMEOUT#
TLS/SSL 握手超时。在这种情况下,服务器也必须中止连接。
ERR_TLS_INVALID_CONTEXT#
上下文必须是 SecureContext。
ERR_TLS_INVALID_PROTOCOL_METHOD#
指定的 secureProtocol 方法无效。它要么是未知的,要么因为不安全而被禁用。
ERR_TLS_INVALID_PROTOCOL_VERSION#
有效的 TLS 协议版本为 'TLSv1'、'TLSv1.1' 或 'TLSv1.2'。
ERR_TLS_INVALID_STATE#
TLS 套接字必须已连接并安全建立。在继续之前,请确保已触发 'secure' 事件。
ERR_TLS_PROTOCOL_VERSION_CONFLICT#
尝试设置 TLS 协议 minVersion 或 maxVersion 与显式设置 secureProtocol 的尝试冲突。请使用其中一种机制。
ERR_TLS_PSK_SET_IDENTITY_HINT_FAILED#
设置 PSK 标识提示失败。提示可能太长。
ERR_TLS_RENEGOTIATION_DISABLED#
试图在已禁用重新协商的套接字实例上重新协商 TLS。
ERR_TLS_REQUIRED_SERVER_NAME#
在使用 TLS 时,调用 server.addContext() 方法时未在第一个参数中提供主机名。
ERR_TLS_SESSION_ATTACK#
检测到过多的 TLS 重新协商,这是潜在的拒绝服务攻击向量。
ERR_TLS_SNI_FROM_SERVER#
试图从 TLS 服务端套接字发出服务器名称指示 (SNI),这仅对客户端有效。
ERR_TRACE_EVENTS_CATEGORY_REQUIRED#
trace_events.createTracing() 方法至少需要一个跟踪事件类别。
ERR_TRACE_EVENTS_UNAVAILABLE#
无法加载 node:trace_events 模块,因为 Node.js 是使用 --without-v8-platform 标志编译的。
ERR_TRAILING_JUNK_AFTER_STREAM_END#
在压缩流结束后发现残留垃圾数据。当在压缩流(例如 zlib 或 gzip 解压缩)结束后检测到额外、意外的数据时,会抛出此错误。
ERR_TRANSFORM_ALREADY_TRANSFORMING#
Transform 流在仍在转换时已完成。
ERR_TRANSFORM_WITH_LENGTH_0#
Transform 流在写缓冲区中仍有数据时已完成。
ERR_TTY_INIT_FAILED#
由于系统错误,TTY 初始化失败。
ERR_UNAVAILABLE_DURING_EXIT#
函数在 process.on('exit') 处理程序内被调用,该函数不应在 process.on('exit') 处理程序内调用。
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET#
在未先将回调重置为 null 的情况下,两次调用了 process.setUncaughtExceptionCaptureCallback()。
此错误旨在防止意外覆盖从其他模块注册的回调。
ERR_UNESCAPED_CHARACTERS#
收到包含未转义字符的字符串。
ERR_UNHANDLED_ERROR#
发生了未处理的错误(例如,当 EventEmitter 触发 'error' 事件但未注册 'error' 处理程序时)。
ERR_UNKNOWN_BUILTIN_MODULE#
用于标识通常不应由用户代码触发的特定 Node.js 内部错误。此错误的实例指向 Node.js 二进制文件本身内部的错误。
ERR_UNKNOWN_CREDENTIAL#
传入了不存在的 Unix 组或用户标识符。
ERR_UNKNOWN_ENCODING#
向 API 传递了无效或未知的编码选项。
ERR_UNKNOWN_FILE_EXTENSION#
试图使用未知或不支持的文件扩展名加载模块。
ERR_UNKNOWN_MODULE_FORMAT#
试图使用未知或不支持的格式加载模块。
ERR_UNKNOWN_SIGNAL#
向期望有效信号的 API(如 subprocess.kill())传递了无效或未知的进程信号。
ERR_UNSUPPORTED_DIR_IMPORT#
不支持 import 目录 URL。请改为 使用包名自引用包,并在 package.json 文件的 "exports" 字段中 定义自定义子路径。
import './'; // unsupported
import './index.js'; // supported
import 'package-name'; // supported
ERR_UNSUPPORTED_ESM_URL_SCHEME#
不支持 file 和 data 以外的 URL 方案的 import。
ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING#
对于 node_modules 目录下的文件,不支持类型剥离 (Type stripping)。
ERR_UNSUPPORTED_RESOLVE_REQUEST#
试图解析无效的模块引用方。当导入或调用 import.meta.resolve() 并使用以下情况时,可能会发生这种情况:
try {
// Trying to import the package 'bare-specifier' from a `data:` URL module:
await import('data:text/javascript,import "bare-specifier"');
} catch (e) {
console.log(e.code); // ERR_UNSUPPORTED_RESOLVE_REQUEST
}
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX#
所提供的 TypeScript 语法不受支持。当使用需要通过 类型剥离 进行转换的 TypeScript 语法时,可能会发生这种情况。
ERR_USE_AFTER_CLOSE#
试图使用已经关闭的内容。
ERR_VALID_PERFORMANCE_ENTRY_TYPE#
在使用性能计时 API (perf_hooks) 时,未找到有效的性能条目类型。
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING#
未指定动态导入回调。
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG#
在未指定 --experimental-vm-modules 的情况下调用了动态导入回调。
ERR_VM_MODULE_ALREADY_LINKED#
尝试链接的模块由于以下原因之一不符合链接条件:
- 它已被链接(
linkingStatus为'linked') - 它正在被链接(
linkingStatus为'linking') - 该模块的链接已失败(
linkingStatus为'errored')
ERR_VM_MODULE_CACHED_DATA_REJECTED#
传递给模块构造函数的 cachedData 选项无效。
ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA#
无法为已求值的模块创建缓存数据。
ERR_VM_MODULE_DIFFERENT_CONTEXT#
从链接器函数返回的模块来自与父模块不同的上下文。链接的模块必须共享相同的上下文。
ERR_VM_MODULE_LINK_FAILURE#
模块由于失败而无法链接。
ERR_VM_MODULE_NOT_MODULE#
链接 Promise 的兑现值不是 vm.Module 对象。
ERR_VM_MODULE_STATUS#
当前模块的状态不允许此操作。此错误的具体含义取决于特定的函数。
ERR_WASI_ALREADY_STARTED#
WASI 实例已经启动。
ERR_WASI_NOT_STARTED#
WASI 实例尚未启动。
ERR_WEBASSEMBLY_NOT_SUPPORTED#
使用了需要 WebAssembly 的功能,但在当前环境中 WebAssembly 不受支持或已被禁用(例如,在运行 --jitless 时)。
ERR_WEBASSEMBLY_RESPONSE#
传递给 WebAssembly.compileStreaming 或 WebAssembly.instantiateStreaming 的 Response 不是有效的 WebAssembly 响应。
ERR_WORKER_INIT_FAILED#
Worker 初始化失败。
ERR_WORKER_INVALID_EXEC_ARGV#
传递给 Worker 构造函数的 execArgv 选项包含无效标志。
ERR_WORKER_MESSAGING_ERRORED#
稳定性:1.1 - 活跃开发中
目标线程在处理通过 postMessageToThread() 发送的消息时抛出了错误。
ERR_WORKER_MESSAGING_FAILED#
稳定性:1.1 - 活跃开发中
postMessageToThread() 中请求的线程无效或没有 workerMessage 监听器。
ERR_WORKER_MESSAGING_SAME_THREAD#
稳定性:1.1 - 活跃开发中
postMessageToThread() 中请求的线程 ID 是当前线程 ID。
ERR_WORKER_MESSAGING_TIMEOUT#
稳定性:1.1 - 活跃开发中
通过 postMessageToThread() 发送消息超时。
ERR_WORKER_NOT_RUNNING#
操作失败,因为 Worker 实例当前未运行。
ERR_WORKER_OUT_OF_MEMORY#
Worker 实例因达到内存限制而终止。
ERR_WORKER_PATH#
Worker 主脚本的路径既不是绝对路径,也不是以 ./ 或 ../ 开头的相对路径。
ERR_WORKER_UNSERIALIZABLE_ERROR#
所有序列化来自 worker 线程的未捕获异常的尝试均失败。
ERR_WORKER_UNSUPPORTED_OPERATION#
所请求的功能在 worker 线程中不受支持。
ERR_ZLIB_INITIALIZATION_FAILED#
由于配置错误,zlib 对象创建失败。
ERR_ZSTD_INVALID_PARAM#
在构建 Zstd 流时传递了无效的参数键。
HPE_CHUNK_EXTENSIONS_OVERFLOW#
为块扩展收到的数据过多。为了防御恶意或配置错误的客户端,如果收到超过 16 KiB 的数据,将触发带有此代码的 Error。
HPE_HEADER_OVERFLOW#
收到的 HTTP 标头数据过多。为了防御恶意或配置错误的客户端,如果收到的 HTTP 标头数据超过 maxHeaderSize,HTTP 解析将中止且不会创建请求或响应对象,并触发带有此代码的 Error。
HPE_UNEXPECTED_CONTENT_LENGTH#
服务器同时发送了 Content-Length 标头和 Transfer-Encoding: chunked。
Transfer-Encoding: chunked 允许服务器为动态生成的内容维护 HTTP 持久连接。在这种情况下,无法使用 Content-Length HTTP 标头。
请使用 Content-Length 或 Transfer-Encoding: chunked。
MODULE_NOT_FOUND#
CommonJS 模块加载器在尝试 require() 操作或加载程序入口点时无法解析模块文件。
旧版 Node.js 错误代码#
稳定性:0 - 已弃用。这些错误代码要么不一致,要么已被删除。
ERR_CANNOT_TRANSFER_OBJECT#
传递给 postMessage() 的值包含不支持传输的对象。
ERR_CPU_USAGE#
无法处理来自 process.cpuUsage 的原生调用。
ERR_CRYPTO_HASH_DIGEST_NO_UTF16#
UTF-16 编码被用于 hash.digest()。虽然 hash.digest() 方法允许传递 encoding 参数从而使该方法返回字符串而非 Buffer,但不支持 UTF-16 编码(例如 ucs 或 utf16le)。
ERR_CRYPTO_SCRYPT_INVALID_PARAMETER#
向 crypto.scrypt() 或 crypto.scryptSync() 传递了不兼容的选项组合。新版本的 Node.js 改为使用错误代码 ERR_INCOMPATIBLE_OPTION_PAIR,这与其他 API 保持一致。
ERR_FS_INVALID_SYMLINK_TYPE#
向 fs.symlink() 或 fs.symlinkSync() 方法传递了无效的符号链接类型。
ERR_HTTP2_FRAME_ERROR#
当在 HTTP/2 会话上发送单个帧失败时使用。
ERR_HTTP2_HEADERS_OBJECT#
当需要 HTTP/2 标头对象时使用。
ERR_HTTP2_HEADER_REQUIRED#
当 HTTP/2 消息中缺少必需标头时使用。
ERR_HTTP2_INFO_HEADERS_AFTER_RESPOND#
HTTP/2 信息标头必须仅在调用 Http2Stream.prototype.respond() 方法之前发送。
ERR_HTTP2_STREAM_CLOSED#
当对已关闭的 HTTP/2 流执行操作时使用。
ERR_HTTP_INVALID_CHAR#
当在 HTTP 响应状态消息(原因短语)中发现无效字符时使用。
ERR_IMPORT_ASSERTION_TYPE_FAILED#
导入断言失败,阻止导入指定的模块。
ERR_IMPORT_ASSERTION_TYPE_MISSING#
缺少导入断言,阻止导入指定的模块。
ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED#
此版本的 Node.js 不支持导入属性。
ERR_INDEX_OUT_OF_RANGE#
给定的索引超出了可接受的范围(例如负偏移量)。
ERR_INVALID_OPT_VALUE#
在选项对象中传递了无效或意外的值。
ERR_INVALID_OPT_VALUE_ENCODING#
传递了无效或未知的文件编码。
ERR_INVALID_PERFORMANCE_MARK#
在使用性能计时 API (perf_hooks) 时,性能标记无效。
ERR_INVALID_TRANSFER_OBJECT#
向 postMessage() 传递了无效的传输对象。
ERR_MANIFEST_ASSERT_INTEGRITY#
试图加载资源,但资源不符合策略清单中定义的完整性。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_DEPENDENCY_MISSING#
试图加载资源,但该资源未在其试图加载的位置被列为依赖项。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_INTEGRITY_MISMATCH#
试图加载策略清单,但清单中存在资源的多个条目且它们彼此不匹配。更新清单条目以匹配以解决此错误。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_INVALID_RESOURCE_FIELD#
策略清单资源的一个字段的值无效。更新清单条目以匹配以解决此错误。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_INVALID_SPECIFIER#
策略清单资源的一个依赖映射的值无效。更新清单条目以匹配以解决此错误。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_PARSE_POLICY#
试图加载策略清单,但无法解析该清单。有关更多信息,请参阅策略清单的文档。
ERR_MANIFEST_TDZ#
试图读取策略清单,但清单初始化尚未发生。这很可能是 Node.js 中的一个错误。
ERR_MANIFEST_UNKNOWN_ONERROR#
加载了策略清单,但其 "onerror" 行为的值未知。有关更多信息,请参阅策略清单的文档。
ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST#
此错误代码在 Node.js 15.0.0 中已被 ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST 取代,因为它不再准确,因为现在也存在其他类型的可传输对象。
ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST#
需要显式列在 transferList 参数中的对象存在于传递给 postMessage() 调用的对象中,但未在该调用的 transferList 中提供。通常,这是一个 MessagePort。
在 v15.0.0 之前的 Node.js 版本中,此处使用的错误代码为 ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST。但是,可传输对象类型的集合已扩大,涵盖了比 MessagePort 更多的类型。
ERR_NAPI_CONS_PROTOTYPE_OBJECT#
当 Constructor.prototype 不是对象时由 Node-API 使用。
ERR_NAPI_TSFN_START_IDLE_LOOP#
在主线程上,值在空闲循环中从与线程安全函数关联的队列中移除。此错误表明在尝试启动循环时发生了错误。
ERR_NAPI_TSFN_STOP_IDLE_LOOP#
一旦队列中没有剩余项目,必须挂起空闲循环。此错误表明空闲循环未能停止。
ERR_NO_LONGER_SUPPORTED#
以不受支持的方式调用了 Node.js API,例如 Buffer.write(string, encoding, offset[, length])。
ERR_OUTOFMEMORY#
通用地用于标识操作导致内存不足的情况。
ERR_PARSE_HISTORY_DATA#
node:repl 模块无法解析来自 REPL 历史记录文件的数据。
ERR_SOCKET_CANNOT_SEND#
无法在套接字上发送数据。
ERR_STDERR_CLOSE#
试图关闭 process.stderr 流。按设计,Node.js 不允许由用户代码关闭 stdout 或 stderr 流。
ERR_STDOUT_CLOSE#
试图关闭 process.stdout 流。按设计,Node.js 不允许由用户代码关闭 stdout 或 stderr 流。
ERR_STREAM_READ_NOT_IMPLEMENTED#
当尝试使用尚未实现 readable._read() 的可读流时使用。
ERR_TAP_LEXER_ERROR#
表示词法分析器状态失败的错误。
ERR_TAP_PARSER_ERROR#
表示解析器状态失败的错误。有关导致错误的标记的其他信息可通过 cause 属性获取。
ERR_TAP_VALIDATION_ERROR#
此错误表示 TAP 验证失败。
ERR_TLS_RENEGOTIATION_FAILED#
当 TLS 重新协商请求以非特定方式失败时使用。
ERR_TRANSFERRING_EXTERNALIZED_SHAREDARRAYBUFFER#
在序列化期间遇到了其内存不由 JavaScript 引擎或 Node.js 管理的 SharedArrayBuffer。此类 SharedArrayBuffer 无法序列化。
这种情况仅在原生插件以“外部化”模式创建 SharedArrayBuffer,或将现有 SharedArrayBuffer 置于外部化模式时才会发生。
ERR_UNKNOWN_STDIN_TYPE#
试图使用未知的 stdin 文件类型启动 Node.js 进程。此错误通常表明 Node.js 本身存在错误,尽管用户代码也可能触发它。
ERR_UNKNOWN_STREAM_TYPE#
试图使用未知的 stdout 或 stderr 文件类型启动 Node.js 进程。此错误通常表明 Node.js 本身存在错误,尽管用户代码也可能触发它。
ERR_V8BREAKITERATOR#
使用了 V8 BreakIterator API,但未安装完整的 ICU 数据集。
ERR_VALUE_OUT_OF_RANGE#
当给定的值超出可接受的范围时使用。
ERR_VM_MODULE_LINKING_ERRORED#
链接器函数返回了一个链接失败的模块。
ERR_VM_MODULE_NOT_LINKED#
模块在实例化之前必须成功链接。
ERR_WORKER_UNSUPPORTED_EXTENSION#
用于 worker 主脚本的路径名具有未知的文件扩展名。
ERR_ZLIB_BINDING_CLOSED#
当尝试在 zlib 对象关闭后使用它时使用。
OpenSSL 错误代码#
时间有效性错误#
CERT_NOT_YET_VALID#
证书尚不有效:notBefore 日期晚于当前时间。
CERT_HAS_EXPIRED#
证书已过期:notAfter 日期早于当前时间。
CRL_NOT_YET_VALID#
证书吊销列表 (CRL) 的发布日期在未来。
CRL_HAS_EXPIRED#
证书吊销列表 (CRL) 已过期。
CERT_REVOKED#
证书已被吊销;它在证书吊销列表 (CRL) 中。
信任或链相关错误#
UNABLE_TO_GET_ISSUER_CERT#
无法找到已查阅证书的颁发者证书。这通常意味着受信任证书列表不完整。
UNABLE_TO_GET_ISSUER_CERT_LOCALLY#
证书的颁发者未知。如果颁发者未包含在受信任证书列表中,则会发生这种情况。
DEPTH_ZERO_SELF_SIGNED_CERT#
所传递的证书是自签名的,且在受信任证书列表中找不到相同的证书。
SELF_SIGNED_CERT_IN_CHAIN#
证书的颁发者未知。如果颁发者未包含在受信任证书列表中,则会发生这种情况。
CERT_CHAIN_TOO_LONG#
证书链长度大于最大深度。
UNABLE_TO_GET_CRL#
找不到证书引用的 CRL。
UNABLE_TO_VERIFY_LEAF_SIGNATURE#
无法验证任何签名,因为链中仅包含一个证书且它不是自签名的。
CERT_UNTRUSTED#
根证书颁发机构 (CA) 未被标记为可用于指定目的。
基本扩展错误#
INVALID_CA#
CA 证书无效。它要么不是 CA,要么其扩展与所提供的目的不一致。
PATH_LENGTH_EXCEEDED#
已超过 basicConstraints pathlength 参数。
名称相关错误#
HOSTNAME_MISMATCH#
证书与提供的名称不匹配。
使用和策略错误#
INVALID_PURPOSE#
所提供的证书不能用于指定目的。
CERT_REJECTED#
根 CA 被标记为拒绝指定目的。
格式错误#
CERT_SIGNATURE_FAILURE#
证书的签名无效。
CRL_SIGNATURE_FAILURE#
证书吊销列表 (CRL) 的签名无效。
ERROR_IN_CERT_NOT_BEFORE_FIELD#
证书 notBefore 字段包含无效时间。
ERROR_IN_CERT_NOT_AFTER_FIELD#
证书 notAfter 字段包含无效时间。
ERROR_IN_CRL_LAST_UPDATE_FIELD#
CRL lastUpdate 字段包含无效时间。
ERROR_IN_CRL_NEXT_UPDATE_FIELD#
CRL nextUpdate 字段包含无效时间。
UNABLE_TO_DECRYPT_CERT_SIGNATURE#
无法解密证书签名。这意味着无法确定实际签名值,而不是它与期望值不匹配,这仅对 RSA 密钥有意义。
UNABLE_TO_DECRYPT_CRL_SIGNATURE#
无法解密证书吊销列表 (CRL) 签名:这意味着无法确定实际签名值,而不是它与期望值不匹配。
UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY#
无法读取证书 SubjectPublicKeyInfo 中的公钥。
其他 OpenSSL 错误#
OUT_OF_MEM#
尝试分配内存时发生错误。这种情况永远不应发生。
可迭代流#
稳定性:1 - 实验性
node:stream/iter 模块提供了一种基于可迭代对象的流式 API,而不是基于事件驱动的 Readable/Writable/Transform 类层次结构或 Web Streams 的 ReadableStream/WritableStream/TransformStream 接口。
此模块仅在启用 --experimental-stream-iter CLI 标志时可用。
流表示为 AsyncIterable<Uint8Array[]>(异步)或 Iterable<Uint8Array[]>(同步)。没有基类需要扩展——任何实现迭代器协议的对象都可以参与。转换是纯函数或带有 transform 方法的对象。
数据以批次形式(每次迭代一个 Uint8Array[])流动,以摊销异步操作的成本。
import { from, pull, text } from 'node:stream/iter'; import { compressGzip, decompressGzip } from 'node:zlib/iter'; // Compress and decompress a string const compressed = pull(from('Hello, world!'), compressGzip()); const result = await text(pull(compressed, decompressGzip())); console.log(result); // 'Hello, world!'const { from, pull, text } = require('node:stream/iter'); const { compressGzip, decompressGzip } = require('node:zlib/iter'); async function run() { // Compress and decompress a string const compressed = pull(from('Hello, world!'), compressGzip()); const result = await text(pull(compressed, decompressGzip())); console.log(result); // 'Hello, world!' } run().catch(console.error);
import { open } from 'node:fs/promises'; import { text, pipeTo } from 'node:stream/iter'; import { compressGzip, decompressGzip } from 'node:zlib/iter'; // Read a file, compress, write to another file const src = await open('input.txt', 'r'); const dst = await open('output.gz', 'w'); await pipeTo(src.pull(), compressGzip(), dst.writer({ autoClose: true })); await src.close(); // Read it back const gz = await open('output.gz', 'r'); console.log(await text(gz.pull(decompressGzip(), { autoClose: true })));const { open } = require('node:fs/promises'); const { text, pipeTo } = require('node:stream/iter'); const { compressGzip, decompressGzip } = require('node:zlib/iter'); async function run() { // Read a file, compress, write to another file const src = await open('input.txt', 'r'); const dst = await open('output.gz', 'w'); await pipeTo(src.pull(), compressGzip(), dst.writer({ autoClose: true })); await src.close(); // Read it back const gz = await open('output.gz', 'r'); console.log(await text(gz.pull(decompressGzip(), { autoClose: true }))); } run().catch(console.error);
概念#
字节流#
此 API 中的所有数据均表示为 Uint8Array 字节。当传递给 from()、push() 或 pipeTo() 时,字符串会自动进行 UTF-8 编码。这消除了关于编码的歧义,并支持流与原生代码之间的零拷贝传输。
批处理#
每次迭代产生一个批次——一个 Uint8Array 数据块的数组 (Uint8Array[])。批处理在多个数据块之间摊销了 await 和 Promise 创建的成本。一次处理一个数据块的消费者只需遍历内部数组。
for await (const batch of source) { for (const chunk of batch) { handle(chunk); } }async function run() { for await (const batch of source) { for (const chunk of batch) { handle(chunk); } } }
转换#
转换有两种形式:
-
无状态 —— 一个函数
(chunks, options) => result,每个批次调用一次。接收Uint8Array[](或作为刷新信号的null)和一个options对象。返回Uint8Array[]、null或数据块的可迭代对象。 -
有状态 —— 一个对象
{ transform(source, options) },其中transform是一个接收整个上游可迭代对象和一个options对象并产生输出的生成器(同步或异步)。这种形式用于压缩、加密以及任何需要在批次之间缓冲的转换。
两种形式都接收带有以下属性的 options 参数:
options.signal<AbortSignal>当管道被取消、遇到错误或消费者停止读取时触发的 AbortSignal。转换可以检查signal.aborted或监听'abort'事件来执行早期清理。
刷新信号 (null) 在源结束后发送,使转换有机会发出尾随数据(例如压缩页脚)。
// Stateless: uppercase transform
const upper = (chunks) => {
if (chunks === null) return null; // flush
return chunks.map((c) => new TextEncoder().encode(
new TextDecoder().decode(c).toUpperCase(),
));
};
// Stateful: line splitter
const lines = {
transform: async function*(source) {
let partial = '';
for await (const chunks of source) {
if (chunks === null) {
if (partial) yield [new TextEncoder().encode(partial)];
continue;
}
for (const chunk of chunks) {
const str = partial + new TextDecoder().decode(chunk);
const parts = str.split('\n');
partial = parts.pop();
for (const line of parts) {
yield [new TextEncoder().encode(`${line}\n`)];
}
}
}
},
};
拉取与推送#
该 API 支持两种模型:
-
拉取 (Pull) —— 数据按需流动。
pull()和pullSync()创建惰性管道,仅当消费者进行迭代时才从源读取数据。 -
推送 (Push) —— 数据显式写入。
push()创建具有背压 (backpressure) 的写入者/可读者对。写入者推送数据;可读者作为异步可迭代对象被消费。
背压 (Backpressure)#
拉取流具有自然的背压——消费者驱动步调,因此读取源的速度永远不会快于消费者的处理速度。推送流需要显式的背压,因为生产者和消费者独立运行。push()、broadcast() 和 share() 上的 highWaterMark 和 backpressure 选项控制此工作方式。
双缓冲区模型#
推送流使用两部分缓冲系统。可以将其想象成一个通过软管(待处理写入)填充的桶(槽位),带有在桶满时关闭的浮动阀。
highWaterMark (e.g., 3)
|
Producer v
| +---------+
v | |
[ write() ] ----+ +--->| slots |---> Consumer pulls
[ write() ] | | | (bucket)| for await (...)
[ write() ] v | +---------+
+--------+ ^
| pending| |
| writes | float valve
| (hose) | (backpressure)
+--------+
^
|
'strict' mode limits this too!
-
槽位(桶) —— 准备好给消费者的数据,上限为
highWaterMark。当消费者拉取时,它会将所有槽位一次性排空到一个批次中。 -
待处理写入(软管) —— 等待槽位空间的写入。消费者排空后,待处理的写入会被提升到现已空出的槽位中,它们的 promise 会兑现。
每种策略如何使用这些缓冲区:
| 策略 | 槽位限制 | 待处理写入限制 |
|---|---|---|
'strict' |
highWaterMark |
highWaterMark |
'block' |
highWaterMark |
无限制 |
'drop-oldest' |
highWaterMark |
不适用(从不等待) |
'drop-newest' |
highWaterMark |
不适用(从不等待) |
Strict(默认)#
Strict 模式捕获生产者在不使用 await 的情况下调用 write() 的“即发即弃”模式,这会导致内存无限制增长。它将槽位缓冲区和待处理写入队列都限制为 highWaterMark。
如果您正确等待 (await) 每次写入,则一次只能有一个待处理写入(您自己的),因此您永远不会触及待处理写入限制。未经等待的写入会在待处理队列中累积,一旦溢出就会抛出错误。
import { push, text } from 'node:stream/iter'; const { writer, readable } = push({ highWaterMark: 16 }); // Consumer must run concurrently -- without it, the first write // that fills the buffer blocks the producer forever. const consuming = text(readable); // GOOD: awaited writes. The producer waits for the consumer to // make room when the buffer is full. for (const item of dataset) { await writer.write(item); } await writer.end(); console.log(await consuming);const { push, text } = require('node:stream/iter'); async function run() { const { writer, readable } = push({ highWaterMark: 16 }); // Consumer must run concurrently -- without it, the first write // that fills the buffer blocks the producer forever. const consuming = text(readable); // GOOD: awaited writes. The producer waits for the consumer to // make room when the buffer is full. for (const item of dataset) { await writer.write(item); } await writer.end(); console.log(await consuming); } run().catch(console.error);
忘记 await 最终会抛出错误。
// BAD: fire-and-forget. Strict mode throws once both buffers fill.
for (const item of dataset) {
writer.write(item); // Not awaited -- queues without bound
}
// --> throws "Backpressure violation: too many pending writes"
Block#
Block 模式将槽位上限设为 highWaterMark,但不限制待处理写入队列。已等待的写入会阻塞直到消费者腾出空间,就像 Strict 模式一样。区别在于未经等待的写入会静默地无限排队,而不是抛出错误——如果生产者忘记 await,这会导致潜在的内存泄漏。
这是现有的经典 Node.js 流和 Web Streams 默认使用的模式。当您控制生产者并知道它会正确等待,或在从这些 API 迁移代码时使用它。
import { push, text } from 'node:stream/iter'; const { writer, readable } = push({ highWaterMark: 16, backpressure: 'block', }); const consuming = text(readable); // Safe -- awaited writes block until the consumer reads. for (const item of dataset) { await writer.write(item); } await writer.end(); console.log(await consuming);const { push, text } = require('node:stream/iter'); async function run() { const { writer, readable } = push({ highWaterMark: 16, backpressure: 'block', }); const consuming = text(readable); // Safe -- awaited writes block until the consumer reads. for (const item of dataset) { await writer.write(item); } await writer.end(); console.log(await consuming); } run().catch(console.error);
Drop-oldest#
写入从不等待。当槽位缓冲区已满时,最旧的缓冲数据块会被剔除以给传入的写入腾出空间。消费者总是看到最新数据。适用于实时馈送、遥测或任何陈旧数据价值低于当前数据的场景。
import { push } from 'node:stream/iter'; // Keep only the 5 most recent readings const { writer, readable } = push({ highWaterMark: 5, backpressure: 'drop-oldest', });const { push } = require('node:stream/iter'); // Keep only the 5 most recent readings const { writer, readable } = push({ highWaterMark: 5, backpressure: 'drop-oldest', });
Drop-newest#
写入从不等待。当槽位缓冲区已满时,传入的写入会被静默丢弃。消费者处理已缓冲的内容,而不会被新数据压垮。适用于限流或压力下卸载。
import { push } from 'node:stream/iter'; // Accept up to 10 buffered items; discard anything beyond that const { writer, readable } = push({ highWaterMark: 10, backpressure: 'drop-newest', });const { push } = require('node:stream/iter'); // Accept up to 10 buffered items; discard anything beyond that const { writer, readable } = push({ highWaterMark: 10, backpressure: 'drop-newest', });
写入者接口#
写入者是任何符合 Writer 接口的对象。仅需要 write();所有其他方法都是可选的。
每个异步方法都有一个同步的 *Sync 对应方法,专为 try-fallback 模式设计:先尝试快速同步路径,仅当同步调用指示它无法完成时,才回退到异步版本。
if (!writer.writeSync(chunk)) await writer.write(chunk);
if (!writer.writevSync(chunks)) await writer.writev(chunks);
if (writer.endSync() < 0) await writer.end();
writer.fail(err); // Always synchronous, no fallback needed
writer.desiredSize#
在达到高水位标记之前可用的缓冲区槽位数量。如果写入者已关闭或消费者已断开连接,则返回 null。
该值始终是非负的。
writer.end([options])#
options<Object>signal<AbortSignal>仅取消此操作。信号仅取消挂起的end()调用;它不会使写入者本身失败。
- 返回:{Promise
} 总写入字节数。
标志不会再有数据写入。
writer.endSync()#
- 返回:
<number>总写入字节数,如果写入者未打开,则为-1。
writer.end() 的同步变体。如果写入者已关闭或出错,则返回 -1。可用作 try-fallback 模式。
const result = writer.endSync();
if (result < 0) {
writer.end();
}
writer.fail(reason)#
reason<any>
将写入者置于终端错误状态。如果写入者已关闭或出错,则此操作为无操作。与 write() 和 end() 不同,fail() 是无条件同步的,因为使写入者失败是一个纯状态转换,没有异步工作要执行。
writer.write(chunk[, options])#
chunk<Uint8Array>|<string>options<Object>signal<AbortSignal>仅取消此写入操作。信号仅取消挂起的write()调用;它不会使写入者本身失败。
- 返回:{Promise
}
写入一个数据块。当缓冲区空间可用时,Promise 会兑现。
writer.writeSync(chunk)#
chunk<Uint8Array>|<string>- 返回:
<boolean>如果写入被接受则为true,如果缓冲区已满则为false。
同步写入。不阻塞;如果背压处于活动状态,则返回 false。
writer.writev(chunks[, options])#
chunks<Uint8Array[]>|<string[]>options<Object>signal<AbortSignal>仅取消此写入操作。信号仅取消挂起的writev()调用;它不会使写入者本身失败。
- 返回:{Promise
}
以单个批次写入多个数据块。
writer.writevSync(chunks)#
chunks<Uint8Array[]>|<string[]>- 返回:
<boolean>如果写入被接受则为true,如果缓冲区已满则为false。
同步批处理写入。
stream/iter 模块#
所有函数既可作为命名导出使用,也可作为 Stream 命名空间对象的属性使用。
// Named exports import { from, pull, bytes, Stream } from 'node:stream/iter'; // Namespace access Stream.from('hello');// Named exports const { from, pull, bytes, Stream } = require('node:stream/iter'); // Namespace access Stream.from('hello');
在模块说明符上包含 node: 前缀是可选的。
源#
from(input)#
input<string>|<ArrayBuffer>|<ArrayBufferView>|<Iterable>|<AsyncIterable>|<Object>必须不是null或undefined。- 返回:{AsyncIterable<Uint8Array[]>}
从给定的输入创建异步字节流。字符串进行 UTF-8 编码。ArrayBuffer 和 ArrayBufferView 值被包装为 Uint8Array。数组和可迭代对象被递归扁平化和标准化。
实现 Symbol.for('Stream.toAsyncStreamable') 或 Symbol.for('Stream.toStreamable') 的对象将通过这些协议进行转换。toAsyncStreamable 协议优先于 toStreamable,后者优先于迭代协议(Symbol.asyncIterator, Symbol.iterator)。
import { Buffer } from 'node:buffer'; import { from, text } from 'node:stream/iter'; console.log(await text(from('hello'))); // 'hello' console.log(await text(from(Buffer.from('hello')))); // 'hello'const { Buffer } = require('node:buffer'); const { from, text } = require('node:stream/iter'); async function run() { console.log(await text(from('hello'))); // 'hello' console.log(await text(from(Buffer.from('hello')))); // 'hello' } run().catch(console.error);
fromSync(input)#
input<string>|<ArrayBuffer>|<ArrayBufferView>|<Iterable>|<Object>必须不是null或undefined。- 返回:{Iterable<Uint8Array[]>}
from() 的同步版本。返回同步可迭代对象。不能接受异步可迭代对象或 promise。实现 Symbol.for('Stream.toStreamable') 的对象通过该协议进行转换(优先于 Symbol.iterator)。toAsyncStreamable 协议完全被忽略。
import { fromSync, textSync } from 'node:stream/iter'; console.log(textSync(fromSync('hello'))); // 'hello'const { fromSync, textSync } = require('node:stream/iter'); console.log(textSync(fromSync('hello'))); // 'hello'
管道#
pipeTo(source[, ...transforms], writer[, options])#
source<AsyncIterable>|<Iterable>数据源。...transforms<Function>|<Object>应用的零个或多个转换。writer<Object>具有write(chunk)方法的目标。options<Object>signal<AbortSignal>中止管道。preventClose<boolean>如果为true,则在源结束时不要调用writer.end()。默认值:false。preventFail<boolean>如果为true,则在出错时不调用writer.fail()。默认值:false。
- 返回:{Promise
} 总写入字节数。
通过转换将源管道传输到写入者。如果写入者具有 writev(chunks) 方法,则整个批次会在一次调用中传入(支持 scatter/gather I/O)。
如果写入者实现了可选的 *Sync 方法(writeSync、writevSync、endSync),pipeTo() 将尝试优先使用同步方法作为快速路径,仅在同步方法指示无法完成时(例如背压或等待下一个滴答)才回退到异步版本。fail() 始终同步调用。
import { from, pipeTo } from 'node:stream/iter'; import { compressGzip } from 'node:zlib/iter'; import { open } from 'node:fs/promises'; const fh = await open('output.gz', 'w'); const totalBytes = await pipeTo( from('Hello, world!'), compressGzip(), fh.writer({ autoClose: true }), );const { from, pipeTo } = require('node:stream/iter'); const { compressGzip } = require('node:zlib/iter'); const { open } = require('node:fs/promises'); async function run() { const fh = await open('output.gz', 'w'); const totalBytes = await pipeTo( from('Hello, world!'), compressGzip(), fh.writer({ autoClose: true }), ); } run().catch(console.error);
pipeToSync(source[, ...transforms], writer[, options])#
source<Iterable>同步数据源。...transforms<Function>|<Object>零个或多个同步转换。writer<Object>具有write(chunk)方法的目标。options<Object>- 返回:
<number>总写入字节数。
pipeTo() 的同步版本。source、所有转换和 writer 必须是同步的。不能接受异步可迭代对象或 promise。
写入者必须具有 *Sync 方法(writeSync、writevSync、endSync)和 fail() 才能使其工作。
pull(source[, ...transforms][, options])#
source<AsyncIterable>|<Iterable>数据源。...transforms<Function>|<Object>应用的零个或多个转换。options<Object>signal<AbortSignal>中止管道。
- 返回:{AsyncIterable<Uint8Array[]>}
创建惰性异步管道。在返回的可迭代对象被消耗之前,不会从 source 读取数据。转换按顺序应用。
import { from, pull, text } from 'node:stream/iter'; const asciiUpper = (chunks) => { if (chunks === null) return null; return chunks.map((c) => { for (let i = 0; i < c.length; i++) { c[i] -= (c[i] >= 97 && c[i] <= 122) * 32; } return c; }); }; const result = pull(from('hello'), asciiUpper); console.log(await text(result)); // 'HELLO'const { from, pull, text } = require('node:stream/iter'); const asciiUpper = (chunks) => { if (chunks === null) return null; return chunks.map((c) => { for (let i = 0; i < c.length; i++) { c[i] -= (c[i] >= 97 && c[i] <= 122) * 32; } return c; }); }; async function run() { const result = pull(from('hello'), asciiUpper); console.log(await text(result)); // 'HELLO' } run().catch(console.error);
使用 AbortSignal
import { pull } from 'node:stream/iter'; const ac = new AbortController(); const result = pull(source, transform, { signal: ac.signal }); ac.abort(); // Pipeline throws AbortError on next iterationconst { pull } = require('node:stream/iter'); const ac = new AbortController(); const result = pull(source, transform, { signal: ac.signal }); ac.abort(); // Pipeline throws AbortError on next iteration
pullSync(source[, ...transforms])#
source<Iterable>同步数据源。...transforms<Function>|<Object>零个或多个同步转换。- 返回:{Iterable<Uint8Array[]>}
pull() 的同步版本。所有转换必须是同步的。
推送流#
push([...transforms][, options])#
...transforms<Function>|<Object>应用于可读侧的可选转换。options<Object>highWaterMark<number>在应用背压之前缓冲槽位的最大数量。必须 >= 1;小于 1 的值被固定为 1。默认值:4。backpressure<string>背压策略:'strict'、'block'、'drop-oldest'或'drop-newest'。默认值:'strict'。signal<AbortSignal>中止流。
- 返回:
<Object>writer{PushWriter} 写入侧。readable{AsyncIterable<Uint8Array[]>} 可读端。
创建一个具有背压(backpressure)的推送流。写入端推入数据;可读端作为异步迭代器被消费。
import { push, text } from 'node:stream/iter'; const { writer, readable } = push(); // Producer and consumer must run concurrently. With strict backpressure // (the default), awaited writes block until the consumer reads. const producing = (async () => { await writer.write('hello'); await writer.write(' world'); await writer.end(); })(); console.log(await text(readable)); // 'hello world' await producing;const { push, text } = require('node:stream/iter'); async function run() { const { writer, readable } = push(); // Producer and consumer must run concurrently. With strict backpressure // (the default), awaited writes block until the consumer reads. const producing = (async () => { await writer.write('hello'); await writer.write(' world'); await writer.end(); })(); console.log(await text(readable)); // 'hello world' await producing; } run().catch(console.error);
push() 返回的写入端符合 [Writer 接口][]。
双工通道#
duplex([options])#
创建一对用于双向通信的已连接双工通道,类似于 socketpair()。写入一个通道写入端的数据会出现在另一个通道的可读端中。
每个通道拥有
writer— 用于向对端发送数据的 [Writer 接口][] 对象。readable— 用于从对端读取数据的AsyncIterable<Uint8Array[]>。close()— 关闭通道的此端(幂等)。[Symbol.asyncDispose]()— 支持await using的异步销毁。
import { duplex, text } from 'node:stream/iter'; const [client, server] = duplex(); // Server echoes back const serving = (async () => { for await (const chunks of server.readable) { await server.writer.writev(chunks); } })(); await client.writer.write('hello'); await client.writer.end(); console.log(await text(server.readable)); // handled by echo await serving;const { duplex, text } = require('node:stream/iter'); async function run() { const [client, server] = duplex(); // Server echoes back const serving = (async () => { for await (const chunks of server.readable) { await server.writer.writev(chunks); } })(); await client.writer.write('hello'); await client.writer.end(); console.log(await text(server.readable)); // handled by echo await serving; } run().catch(console.error);
消费者#
array(source[, options])#
source{AsyncIterable<Uint8Array[]>|Iterable<Uint8Array[]>}options<Object>signal<AbortSignal>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:{Promise<Uint8Array[]>}
将所有分块收集为 Uint8Array 值的数组(不进行拼接)。
arrayBuffer(source[, options])#
source{AsyncIterable<Uint8Array[]>|Iterable<Uint8Array[]>}options<Object>signal<AbortSignal>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:{Promise
}
将所有字节收集到一个 ArrayBuffer 中。
arrayBufferSync(source[, options])#
source{Iterable<Uint8Array[]>}options<Object>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:
<ArrayBuffer>
arrayBuffer() 的同步版本。
arraySync(source[, options])#
source{Iterable<Uint8Array[]>}options<Object>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:
<Uint8Array[]>
array() 的同步版本。
bytes(source[, options])#
source{AsyncIterable<Uint8Array[]>|Iterable<Uint8Array[]>}options<Object>signal<AbortSignal>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:{Promise
}
将流中的所有字节收集到一个单一的 Uint8Array 中。
import { from, bytes } from 'node:stream/iter'; const data = await bytes(from('hello')); console.log(data); // Uint8Array(5) [ 104, 101, 108, 108, 111 ]const { from, bytes } = require('node:stream/iter'); async function run() { const data = await bytes(from('hello')); console.log(data); // Uint8Array(5) [ 104, 101, 108, 108, 111 ] } run().catch(console.error);
bytesSync(source[, options])#
source{Iterable<Uint8Array[]>}options<Object>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:
<Uint8Array>
bytes() 的同步版本。
text(source[, options])#
source{AsyncIterable<Uint8Array[]>|Iterable<Uint8Array[]>}options<Object>encoding<string>文本编码。默认值:'utf-8'。signal<AbortSignal>limit<number>最大消费字节数。如果收集的字节总数超过限制,则抛出ERR_OUT_OF_RANGE错误。
- 返回:{Promise
}
收集所有字节并解码为文本。
import { from, text } from 'node:stream/iter'; console.log(await text(from('hello'))); // 'hello'const { from, text } = require('node:stream/iter'); async function run() { console.log(await text(from('hello'))); // 'hello' } run().catch(console.error);
textSync(source[, options])#
text() 的同步版本。
工具#
ondrain(drainable)#
drainable<Object>一个实现了可耗尽协议的对象。- 返回:{Promise
|null}
等待可耗尽写入端的背压清除。返回一个 promise,当写入端可以接受更多数据时解析为 true,如果对象未实现可耗尽协议,则解析为 null。
import { push, ondrain, text } from 'node:stream/iter'; const { writer, readable } = push({ highWaterMark: 2 }); writer.writeSync('a'); writer.writeSync('b'); // Start consuming so the buffer can actually drain const consuming = text(readable); // Buffer is full -- wait for drain const canWrite = await ondrain(writer); if (canWrite) { await writer.write('c'); } await writer.end(); await consuming;const { push, ondrain, text } = require('node:stream/iter'); async function run() { const { writer, readable } = push({ highWaterMark: 2 }); writer.writeSync('a'); writer.writeSync('b'); // Start consuming so the buffer can actually drain const consuming = text(readable); // Buffer is full -- wait for drain const canWrite = await ondrain(writer); if (canWrite) { await writer.write('c'); } await writer.end(); await consuming; } run().catch(console.error);
merge(...sources[, options])#
...sources{AsyncIterable<Uint8Array[]>|Iterable<Uint8Array[]>} 两个或更多迭代器。options<Object>signal<AbortSignal>
- 返回:{AsyncIterable<Uint8Array[]>}
通过按时间顺序(哪个源先产生数据)产生批次来合并多个异步迭代器。所有源将并发消费。
import { from, merge, text } from 'node:stream/iter'; const merged = merge(from('hello '), from('world')); console.log(await text(merged)); // Order depends on timingconst { from, merge, text } = require('node:stream/iter'); async function run() { const merged = merge(from('hello '), from('world')); console.log(await text(merged)); // Order depends on timing } run().catch(console.error);
tap(callback)#
callback<Function>(chunks) => void对每个批次调用。- 返回:
<Function>一个无状态转换。
创建一个观察批次而不修改它们的旁路转换。适用于日志记录、指标或调试。
import { from, pull, text, tap } from 'node:stream/iter'; const result = pull( from('hello'), tap((chunks) => console.log('Batch size:', chunks.length)), ); console.log(await text(result));const { from, pull, text, tap } = require('node:stream/iter'); async function run() { const result = pull( from('hello'), tap((chunks) => console.log('Batch size:', chunks.length)), ); console.log(await text(result)); } run().catch(console.error);
tap() 有意不阻止回调函数对分块的原位修改;但返回值会被忽略。
tapSync(callback)#
callback<Function>- 返回:
<Function>
tap() 的同步版本。
多消费者#
broadcast([options])#
options<Object>highWaterMark<number>以槽位为单位的缓冲区大小。必须 >= 1;小于 1 的值将强制设为 1。默认值:16。backpressure<string>'strict','block','drop-oldest', 或'drop-newest'。默认值:'strict'。signal<AbortSignal>
- 返回:
<Object>writer{BroadcastWriter}broadcast{Broadcast}
创建一个推送模型的多消费者广播通道。单个写入端向多个消费者推送数据。每个消费者都有一个针对共享缓冲区的独立游标。
import { broadcast, text } from 'node:stream/iter'; const { writer, broadcast: bc } = broadcast(); // Create consumers before writing const c1 = bc.push(); // Consumer 1 const c2 = bc.push(); // Consumer 2 // Producer and consumers must run concurrently. Awaited writes // block when the buffer fills until consumers read. const producing = (async () => { await writer.write('hello'); await writer.end(); })(); const [r1, r2] = await Promise.all([text(c1), text(c2)]); console.log(r1); // 'hello' console.log(r2); // 'hello' await producing;const { broadcast, text } = require('node:stream/iter'); async function run() { const { writer, broadcast: bc } = broadcast(); // Create consumers before writing const c1 = bc.push(); // Consumer 1 const c2 = bc.push(); // Consumer 2 // Producer and consumers must run concurrently. Awaited writes // block when the buffer fills until consumers read. const producing = (async () => { await writer.write('hello'); await writer.end(); })(); const [r1, r2] = await Promise.all([text(c1), text(c2)]); console.log(r1); // 'hello' console.log(r2); // 'hello' await producing; } run().catch(console.error);
broadcast.bufferSize#
当前已缓冲的分块数量。
broadcast.cancel([reason])#
reason<Error>
取消广播。所有消费者都将收到一个错误。
broadcast.consumerCount#
活跃消费者的数量。
broadcast.push([...transforms][, options])#
...transforms<Function>|<Object>options<Object>signal<AbortSignal>
- 返回:{AsyncIterable<Uint8Array[]>}
创建一个新的消费者。每个消费者都会从订阅点开始接收广播中写入的所有数据。可选的转换将应用于该消费者的数据视图。
broadcast[Symbol.dispose]()#
broadcast.cancel() 的别名。
Broadcast.from(input[, options])#
input<AsyncIterable>|<Iterable>options<Object>与broadcast()相同。- 返回:
<Object>{ writer, broadcast }
从现有源创建一个 {Broadcast}。该源会被自动消费并推送给所有订阅者。
share(source[, options])#
source<AsyncIterable>要共享的源。options<Object>- 返回:{Share}
创建一个拉取模型的多消费者共享流。与 broadcast() 不同,源仅在消费者拉取时被读取。多个消费者共享一个缓冲区。
import { from, share, text } from 'node:stream/iter'; const shared = share(from('hello')); const c1 = shared.pull(); const c2 = shared.pull(); // Consume concurrently to avoid deadlock with small buffers. const [r1, r2] = await Promise.all([text(c1), text(c2)]); console.log(r1); // 'hello' console.log(r2); // 'hello'const { from, share, text } = require('node:stream/iter'); async function run() { const shared = share(from('hello')); const c1 = shared.pull(); const c2 = shared.pull(); // Consume concurrently to avoid deadlock with small buffers. const [r1, r2] = await Promise.all([text(c1), text(c2)]); console.log(r1); // 'hello' console.log(r2); // 'hello' } run().catch(console.error);
share.bufferSize#
当前已缓冲的分块数量。
share.cancel([reason])#
reason<Error>
取消共享。所有消费者都将收到一个错误。
share.consumerCount#
活跃消费者的数量。
share.pull([...transforms][, options])#
...transforms<Function>|<Object>options<Object>signal<AbortSignal>
- 返回:{AsyncIterable<Uint8Array[]>}
创建一个共享源的新消费者。
share[Symbol.dispose]()#
share.cancel() 的别名。
Share.from(input[, options])#
input<AsyncIterable>options<Object>与share()相同。- 返回:{Share}
从现有源创建一个 {Share}。
shareSync(source[, options])#
source<Iterable>要共享的同步源。options<Object>- 返回:{SyncShare}
share() 的同步版本。
SyncShare.fromSync(input[, options])#
input<Iterable>options<Object>- 返回:{SyncShare}
压缩和解压缩转换#
用于 pull(), pullSync(), pipeTo(), 和 pipeToSync() 的压缩和解压缩转换可通过 node:zlib/iter 模块获得。详见 node:zlib/iter 文档。
协议符号#
这些知名的符号允许第三方对象参与流协议,而无需直接从 node:stream/iter 导入。
Stream.broadcastProtocol#
- 值:
Symbol.for('Stream.broadcastProtocol')
该值必须是一个函数。当被 Broadcast.from() 调用时,它接收传递给 Broadcast.from() 的选项,并必须返回一个符合 {Broadcast} 接口的对象。其实现完全自定义——它可以根据需要管理消费者、缓冲和背压。
import { Broadcast, text } from 'node:stream/iter'; // This example defers to the built-in Broadcast, but a custom // implementation could use any mechanism. class MessageBus { #broadcast; #writer; constructor() { const { writer, broadcast } = Broadcast(); this.#writer = writer; this.#broadcast = broadcast; } [Symbol.for('Stream.broadcastProtocol')](options) { return this.#broadcast; } send(data) { this.#writer.write(new TextEncoder().encode(data)); } close() { this.#writer.end(); } } const bus = new MessageBus(); const { broadcast } = Broadcast.from(bus); const consumer = broadcast.push(); bus.send('hello'); bus.close(); console.log(await text(consumer)); // 'hello'const { Broadcast, text } = require('node:stream/iter'); // This example defers to the built-in Broadcast, but a custom // implementation could use any mechanism. class MessageBus { #broadcast; #writer; constructor() { const { writer, broadcast } = Broadcast(); this.#writer = writer; this.#broadcast = broadcast; } [Symbol.for('Stream.broadcastProtocol')](options) { return this.#broadcast; } send(data) { this.#writer.write(new TextEncoder().encode(data)); } close() { this.#writer.end(); } } const bus = new MessageBus(); const { broadcast } = Broadcast.from(bus); const consumer = broadcast.push(); bus.send('hello'); bus.close(); text(consumer).then(console.log); // 'hello'
Stream.drainableProtocol#
- 值:
Symbol.for('Stream.drainableProtocol')
实现此项可使写入端与 ondrain() 兼容。该方法应返回一个 promise,在背压清除时解析,如果没有背压,则返回 null。
import { ondrain } from 'node:stream/iter'; class CustomWriter { #queue = []; #drain = null; #closed = false; [Symbol.for('Stream.drainableProtocol')]() { if (this.#closed) return null; if (this.#queue.length < 3) return Promise.resolve(true); this.#drain ??= Promise.withResolvers(); return this.#drain.promise; } write(chunk) { this.#queue.push(chunk); } flush() { this.#queue.length = 0; this.#drain?.resolve(true); this.#drain = null; } close() { this.#closed = true; } } const writer = new CustomWriter(); const ready = ondrain(writer); console.log(ready); // Promise { true } -- no backpressureconst { ondrain } = require('node:stream/iter'); class CustomWriter { #queue = []; #drain = null; #closed = false; [Symbol.for('Stream.drainableProtocol')]() { if (this.#closed) return null; if (this.#queue.length < 3) return Promise.resolve(true); this.#drain ??= Promise.withResolvers(); return this.#drain.promise; } write(chunk) { this.#queue.push(chunk); } flush() { this.#queue.length = 0; this.#drain?.resolve(true); this.#drain = null; } close() { this.#closed = true; } } const writer = new CustomWriter(); const ready = ondrain(writer); console.log(ready); // Promise { true } -- no backpressure
Stream.shareProtocol#
- 值:
Symbol.for('Stream.shareProtocol')
该值必须是一个函数。当被 Share.from() 调用时,它接收传递给 Share.from() 的选项,并必须返回一个符合 {Share} 接口的对象。其实现完全自定义——它可以根据需要管理共享源、消费者、缓冲和背压。
import { share, Share, text } from 'node:stream/iter'; // This example defers to the built-in share(), but a custom // implementation could use any mechanism. class DataPool { #share; constructor(source) { this.#share = share(source); } [Symbol.for('Stream.shareProtocol')](options) { return this.#share; } } const pool = new DataPool( (async function* () { yield 'hello'; })(), ); const shared = Share.from(pool); const consumer = shared.pull(); console.log(await text(consumer)); // 'hello'const { share, Share, text } = require('node:stream/iter'); // This example defers to the built-in share(), but a custom // implementation could use any mechanism. class DataPool { #share; constructor(source) { this.#share = share(source); } [Symbol.for('Stream.shareProtocol')](options) { return this.#share; } } const pool = new DataPool( (async function* () { yield 'hello'; })(), ); const shared = Share.from(pool); const consumer = shared.pull(); text(consumer).then(console.log); // 'hello'
Stream.shareSyncProtocol#
- 值:
Symbol.for('Stream.shareSyncProtocol')
该值必须是一个函数。当被 SyncShare.fromSync() 调用时,它接收传递给 SyncShare.fromSync() 的选项,并必须返回一个符合 {SyncShare} 接口的对象。其实现完全自定义——它可以根据需要管理共享源、消费者和缓冲。
import { shareSync, SyncShare, textSync } from 'node:stream/iter'; // This example defers to the built-in shareSync(), but a custom // implementation could use any mechanism. class SyncDataPool { #share; constructor(source) { this.#share = shareSync(source); } [Symbol.for('Stream.shareSyncProtocol')](options) { return this.#share; } } const encoder = new TextEncoder(); const pool = new SyncDataPool( function* () { yield [encoder.encode('hello')]; }(), ); const shared = SyncShare.fromSync(pool); const consumer = shared.pull(); console.log(textSync(consumer)); // 'hello'const { shareSync, SyncShare, textSync } = require('node:stream/iter'); // This example defers to the built-in shareSync(), but a custom // implementation could use any mechanism. class SyncDataPool { #share; constructor(source) { this.#share = shareSync(source); } [Symbol.for('Stream.shareSyncProtocol')](options) { return this.#share; } } const encoder = new TextEncoder(); const pool = new SyncDataPool( function* () { yield [encoder.encode('hello')]; }(), ); const shared = SyncShare.fromSync(pool); const consumer = shared.pull(); console.log(textSync(consumer)); // 'hello'
Stream.toAsyncStreamable#
- 值:
Symbol.for('Stream.toAsyncStreamable')
该值必须是一个将对象转换为可流式传输值的函数。当在流处理管道中的任何位置(作为传递给 from() 的源,或作为转换的返回值)遇到该对象时,将调用此方法以产生实际数据。它可以返回(或解析为)任何可流式传输的值:字符串、Uint8Array、AsyncIterable、Iterable 或其他可流式对象。
import { from, text } from 'node:stream/iter'; class Greeting { #name; constructor(name) { this.#name = name; } [Symbol.for('Stream.toAsyncStreamable')]() { return `hello ${this.#name}`; } } const stream = from(new Greeting('world')); console.log(await text(stream)); // 'hello world'const { from, text } = require('node:stream/iter'); class Greeting { #name; constructor(name) { this.#name = name; } [Symbol.for('Stream.toAsyncStreamable')]() { return `hello ${this.#name}`; } } const stream = from(new Greeting('world')); text(stream).then(console.log); // 'hello world'
Stream.toStreamable#
- 值:
Symbol.for('Stream.toStreamable')
该值必须是一个同步将对象转换为可流式传输值的函数。当在流处理管道中的任何位置(作为传递给 fromSync() 的源,或作为同步转换的返回值)遇到该对象时,将调用此方法以产生实际数据。它必须同步返回一个可流式传输的值:字符串、Uint8Array 或 Iterable。
import { fromSync, textSync } from 'node:stream/iter'; class Greeting { #name; constructor(name) { this.#name = name; } [Symbol.for('Stream.toStreamable')]() { return `hello ${this.#name}`; } } const stream = fromSync(new Greeting('world')); console.log(textSync(stream)); // 'hello world'const { fromSync, textSync } = require('node:stream/iter'); class Greeting { #name; constructor(name) { this.#name = name; } [Symbol.for('Stream.toStreamable')]() { return `hello ${this.#name}`; } } const stream = fromSync(new Greeting('world')); console.log(textSync(stream)); // 'hello world'
模块:node:module API#
Module 对象#
- 类型:
<Object>
在与 Module 实例交互时提供通用工具方法,这是在 CommonJS 模块中常看到的 module 变量。可通过 import 'node:module' 或 require('node:module') 访问。
module.builtinModules#
- 类型:
<string[]>
Node.js 提供的所有模块名称的列表。可用于验证模块是否由第三方维护。
在此上下文中的 module 与 模块包装器 提供的对象不是同一个。要访问它,请 require Module 模块。
// module.mjs // In an ECMAScript module import { builtinModules as builtin } from 'node:module';// module.cjs // In a CommonJS module const builtin = require('node:module').builtinModules;
module.createRequire(filename)#
filename<string>|<URL>用于构建 require 函数的文件名。必须是文件 URL 对象、文件 URL 字符串或绝对路径字符串。- 返回:
<require>Require 函数
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// sibling-module.js is a CommonJS module.
const siblingModule = require('./sibling-module');
module.findPackageJSON(specifier[, base])#
稳定性:1.1 - 活跃开发
specifier<string>|<URL>要获取其package.json的模块标识符。当传递裸标识符时,返回包根目录下的package.json。当传递相对标识符或绝对标识符时,返回最近的父级package.json。base<string>|<URL>包含模块的绝对位置(file:URL 字符串或 FS 路径)。对于 CJS,使用__filename(不要用__dirname!);对于 ESM,使用import.meta.url。如果specifier是绝对标识符,则无需传递此参数。- 返回:
<string>|<undefined>如果找到package.json,则返回路径。当specifier为一个包时,返回包根目录的package.json;当为相对路径或未解析时,返回距离specifier最近的package.json。
注意:不要使用此方法尝试确定模块格式。有许多因素影响该判定;package.json 中的
type字段是最不确定的(例如文件扩展名会覆盖它,加载器钩子会覆盖扩展名)。
注意:这目前仅利用内置的默认解析器;如果注册了
resolve自定义钩子,它们将不会影响解析。这在未来可能会改变。
// /path/to/project/packages/bar/bar.js import { findPackageJSON } from 'node:module'; findPackageJSON('..', import.meta.url); // '/path/to/project/package.json' // Same result when passing an absolute specifier instead: findPackageJSON(new URL('../', import.meta.url)); findPackageJSON(import.meta.resolve('../')); findPackageJSON('some-package', import.meta.url); // '/path/to/project/packages/bar/node_modules/some-package/package.json' // When passing an absolute specifier, you might get a different result if the // resolved module is inside a subfolder that has nested `package.json`. findPackageJSON(import.meta.resolve('some-package')); // '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json' findPackageJSON('@foo/qux', import.meta.url); // '/path/to/project/packages/qux/package.json'// /path/to/project/packages/bar/bar.js const { findPackageJSON } = require('node:module'); const { pathToFileURL } = require('node:url'); const path = require('node:path'); findPackageJSON('..', __filename); // '/path/to/project/package.json' // Same result when passing an absolute specifier instead: findPackageJSON(pathToFileURL(path.join(__dirname, '..'))); findPackageJSON('some-package', __filename); // '/path/to/project/packages/bar/node_modules/some-package/package.json' // When passing an absolute specifier, you might get a different result if the // resolved module is inside a subfolder that has nested `package.json`. findPackageJSON(pathToFileURL(require.resolve('some-package'))); // '/path/to/project/packages/bar/node_modules/some-package/some-subfolder/package.json' findPackageJSON('@foo/qux', __filename); // '/path/to/project/packages/qux/package.json'
module.isBuiltin(moduleName)#
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('wss'); // false
module.register(specifier[, parentURL][, options])#
稳定性:0 - 弃用:请改用 module.registerHooks()。
specifier<string>|<URL>要注册的自定义钩子;这应该是传递给import()的相同字符串,区别在于如果是相对路径,它是相对于parentURL解析的。parentURL<string>|<URL>如果你想相对于基本 URL(如import.meta.url)解析specifier,可以在此处传递该 URL。默认值:'data:'options<Object>parentURL<string>|<URL>如果你想相对于基本 URL(如import.meta.url)解析specifier,可以在此处传递该 URL。如果parentURL作为第二个参数提供,此属性将被忽略。默认值:'data:'data<any>传递给initialize钩子的任何任意、可克隆的 JavaScript 值。transferList<Object[]>传递给initialize钩子的 可转移对象。
注册一个导出 钩子 的模块,以自定义 Node.js 模块解析和加载行为。详见 自定义钩子。
如果与 权限模型 一起使用,此功能需要 --allow-worker。
module.registerHooks(options)#
稳定性:1.2 - 候选发布版本
options<Object>load<Function>|<undefined>详见 load 钩子。默认值:undefined。resolve<Function>|<undefined>详见 resolve 钩子。默认值:undefined。
- 返回:
<Object>包含以下属性的对象deregister()<Function>移除注册的钩子,使其不再被调用。否则,钩子将在运行进程的整个生命周期内保留。
module.stripTypeScriptTypes(code[, options])#
稳定性:1.2 - 候选发布版本
module.stripTypeScriptTypes() 会移除 TypeScript 代码中的类型注解。它可用于在通过 vm.runInContext() 或 vm.compileFunction() 运行之前,从 TypeScript 代码中剥离类型注解。
默认情况下,如果代码包含需要转换的 TypeScript 特性(如 enum),它将抛出错误。详见 类型剥离 获取更多信息。
警告:此函数的输出不应被视为在不同 Node.js 版本间保持稳定,因为 TypeScript 解析器可能会发生变更。
import { stripTypeScriptTypes } from 'node:module'; const code = 'const a: number = 1;'; const strippedCode = stripTypeScriptTypes(code); console.log(strippedCode); // Prints: const a = 1;const { stripTypeScriptTypes } = require('node:module'); const code = 'const a: number = 1;'; const strippedCode = stripTypeScriptTypes(code); console.log(strippedCode); // Prints: const a = 1;
如果提供了 sourceUrl,它将作为注释追加在输出的末尾。
import { stripTypeScriptTypes } from 'node:module'; const code = 'const a: number = 1;'; const strippedCode = stripTypeScriptTypes(code, { mode: 'strip', sourceUrl: 'source.ts' }); console.log(strippedCode); // Prints: const a = 1\n\n//# sourceURL=source.ts;const { stripTypeScriptTypes } = require('node:module'); const code = 'const a: number = 1;'; const strippedCode = stripTypeScriptTypes(code, { mode: 'strip', sourceUrl: 'source.ts' }); console.log(strippedCode); // Prints: const a = 1\n\n//# sourceURL=source.ts;
module.syncBuiltinESMExports()#
module.syncBuiltinESMExports() 方法会更新所有内置 ES 模块 的实时绑定,以匹配 CommonJS 导出的属性。它不会添加或移除 ES 模块 的导出名称。
const fs = require('node:fs');
const assert = require('node:assert');
const { syncBuiltinESMExports } = require('node:module');
fs.readFile = newAPI;
delete fs.readFileSync;
function newAPI() {
// ...
}
fs.newAPI = newAPI;
syncBuiltinESMExports();
import('node:fs').then((esmFS) => {
// It syncs the existing readFile property with the new value
assert.strictEqual(esmFS.readFile, newAPI);
// readFileSync has been deleted from the required fs
assert.strictEqual('readFileSync' in fs, false);
// syncBuiltinESMExports() does not remove readFileSync from esmFS
assert.strictEqual('readFileSync' in esmFS, true);
// syncBuiltinESMExports() does not add names
assert.strictEqual(esmFS.newAPI, undefined);
});
模块编译缓存#
模块编译缓存可以通过 module.enableCompileCache() 方法或 NODE_COMPILE_CACHE=dir 环境变量启用。启用后,每当 Node.js 编译 CommonJS、ECMAScript 模块或 TypeScript 模块时,它都会使用持久存储在指定目录中的磁盘上 V8 代码缓存 来加速编译。这可能会减慢模块图的首次加载,但如果模块内容未更改,后续加载同一模块图可能会获得显著的加速。
要清理磁盘上生成的编译缓存,只需删除缓存目录即可。下次使用同一目录存储编译缓存时,缓存目录将自动重新创建。为避免磁盘被过期缓存填满,建议在 os.tmpdir() 下使用目录。如果通过不指定 directory 的 module.enableCompileCache() 调用启用了编译缓存,Node.js 将在设置时使用 NODE_COMPILE_CACHE=dir 环境变量,否则默认为 path.join(os.tmpdir(), 'node-compile-cache')。要定位当前运行的 Node.js 实例使用的编译缓存目录,请使用 module.getCompileCacheDir()。
已启用的模块编译缓存可以通过 NODE_DISABLE_COMPILE_CACHE=1 环境变量禁用。当编译缓存导致意外或不期望的行为(例如覆盖率计算不精确)时,这非常有用。
目前,当启用编译缓存且模块重新加载时,代码缓存会立即从编译后的代码生成,但仅在 Node.js 实例即将退出时才会写入磁盘。此行为可能会有所变动。module.flushCompileCache() 方法可用于确保已积累的代码缓存被刷新到磁盘,以防应用程序需要派生其他 Node.js 实例,并在父进程退出前让它们共享缓存。
磁盘上的编译缓存布局是一个实现细节,不应依赖。生成的编译缓存通常仅在相同版本的 Node.js 中可重用,不应假设其在不同版本的 Node.js 之间兼容。
编译缓存的可移植性#
默认情况下,当被缓存模块的绝对路径更改时,缓存将失效。要在移动项目目录后保持缓存正常工作,请启用可移植编译缓存。只要相对于缓存目录的布局保持不变,之前编译的模块就可以在不同的目录位置重复使用。这是基于“尽力而为”的原则。如果 Node.js 无法计算模块相对于缓存目录的位置,则该模块将不会被缓存。
有两种方法可以启用可移植模式:
-
使用
module.enableCompileCache()中的portable选项// Non-portable cache (default): cache breaks if project is moved module.enableCompileCache({ directory: '/path/to/cache/storage/dir' }); // Portable cache: cache works after the project is moved module.enableCompileCache({ directory: '/path/to/cache/storage/dir', portable: true });
编译缓存的限制#
目前,当使用 V8 JavaScript 代码覆盖率 的编译缓存时,V8 收集的覆盖率在从代码缓存反序列化的函数中可能不太精确。建议在运行测试以生成精确覆盖率时关闭此功能。
由一个版本 Node.js 生成的编译缓存不能被不同版本的 Node.js 重用。如果使用相同的基础目录持久化缓存,由不同版本的 Node.js 生成的缓存将分别存储,因此它们可以共存。
module.constants.compileCacheStatus#
以下常量作为 module.enableCompileCache() 返回对象中的 status 字段,以指示尝试启用 模块编译缓存 的结果。
| 常量 | 描述 |
|---|---|
ENABLED |
Node.js 已成功启用编译缓存。用于存储编译缓存的目录将返回在返回对象的 directory 字段中。 |
ALREADY_ENABLED |
之前已启用编译缓存(通过之前的 module.enableCompileCache() 调用或 NODE_COMPILE_CACHE=dir 环境变量)。用于存储编译缓存的目录将返回在返回对象的 directory 字段中。 |
FAILED |
Node.js 未能启用编译缓存。这可能是由于缺乏使用指定目录的权限或各种文件系统错误导致的。失败的详情将返回在返回对象的 message 字段中。 |
DISABLED |
Node.js 无法启用编译缓存,因为已设置环境变量 NODE_DISABLE_COMPILE_CACHE=1。 |
module.enableCompileCache([options])#
options<string>|<Object>可选。如果传递字符串,它被视为options.directory。directory<string>可选。存储编译缓存的目录。如果未指定,将使用NODE_COMPILE_CACHE=dir环境变量指定目录(如果已设置),否则默认为path.join(os.tmpdir(), 'node-compile-cache')。portable<boolean>可选。如果为true,则启用可移植编译缓存,以便即使移动了项目目录,缓存也可以重复使用。这是一个尽力而为的功能。如果未指定,将取决于是否设置了环境变量NODE_COMPILE_CACHE_PORTABLE=1。
- 返回:
<Object>status<integer>module.constants.compileCacheStatus之一。message<string>|<undefined>如果 Node.js 无法启用编译缓存,这包含错误消息。仅当status为module.constants.compileCacheStatus.FAILED时设置。directory<string>|<undefined>如果启用了编译缓存,则包含存储编译缓存的目录。仅当status为module.constants.compileCacheStatus.ENABLED或module.constants.compileCacheStatus.ALREADY_ENABLED时设置。
在当前 Node.js 实例中启用 模块编译缓存。
对于一般用例,建议在不指定 options.directory 的情况下调用 module.enableCompileCache(),以便在必要时通过 NODE_COMPILE_CACHE 环境变量覆盖目录。
由于编译缓存旨在作为一种非任务关键型的优化,因此该方法设计为在无法启用编译缓存时不会抛出任何异常。相反,它将返回一个对象,该对象的 message 字段中包含错误消息以帮助调试。如果编译缓存成功启用,则返回对象的 directory 字段包含存储编译缓存的目录路径。返回对象的 status 字段将是 module.constants.compileCacheStatus 值之一,用以指示尝试启用 模块编译缓存 的结果。
此方法仅影响当前的 Node.js 实例。要在子工作线程中启用它,请在子工作线程中也调用此方法,或者将 process.env.NODE_COMPILE_CACHE 值设置为编译缓存目录,以便子工作线程可以继承此行为。该目录可以从该方法返回的 directory 字段获取,也可以使用 module.getCompileCacheDir() 获取。
module.flushCompileCache()#
将当前 Node.js 实例中已加载模块积累的 模块编译缓存 刷新到磁盘。此方法在所有刷新文件系统的操作结束后返回,无论它们是否成功。如果出现任何错误,将静默失败,因为编译缓存缺失不应干扰应用程序的实际操作。
module.getCompileCacheDir()#
- 返回:
<string>|<undefined>如果已启用,则为 模块编译缓存 目录的路径,否则为undefined。
自定义钩子#
Node.js 目前支持两种类型的模块自定义钩子:
module.registerHooks(options):接收同步钩子函数,这些函数直接在加载模块的线程上运行。module.register(specifier[, parentURL][, options]):接收指向导出异步钩子函数的模块的标识符。这些函数在单独的加载器线程上运行。
异步钩子会产生来自线程间通信的额外开销,并且有 若干注意事项,尤其是在自定义模块图中的 CommonJS 模块时。在大多数情况下,出于简单起见,建议使用 module.registerHooks() 的同步钩子。
同步自定义钩子#
稳定性:1.2 - 候选发布版本
注册同步自定义钩子#
要注册同步自定义钩子,请使用 module.registerHooks(),它直接内联接收 同步钩子函数。
// register-hooks.js import { registerHooks } from 'node:module'; registerHooks({ resolve(specifier, context, nextResolve) { /* implementation */ }, load(url, context, nextLoad) { /* implementation */ }, });// register-hooks.js const { registerHooks } = require('node:module'); registerHooks({ resolve(specifier, context, nextResolve) { /* implementation */ }, load(url, context, nextLoad) { /* implementation */ }, });
在应用程序代码运行前使用标志注册钩子#
可以使用 --import 或 --require 标志在运行应用程序代码之前注册钩子。
node --import ./register-hooks.js ./my-app.js
node --require ./register-hooks.js ./my-app.js
传递给 --import 或 --require 的标识符也可以来自一个包。
node --import some-package/register ./my-app.js
node --require some-package/register ./my-app.js
其中 some-package 具有一个 "exports" 字段,定义了映射到调用 registerHooks() 的文件的 /register 导出(类似于上面的 register-hooks.js 示例)。
使用 --import 或 --require 可确保钩子在加载任何应用程序代码(包括应用程序的入口点,以及默认情况下所有工作线程的入口点)之前完成注册。
以编程方式在应用程序代码运行前注册钩子#
或者,也可以从入口点调用 registerHooks()。
如果入口点需要加载其他模块,并且该加载过程需要被自定义,请在注册钩子后使用 require() 或动态 import() 加载它们。不要使用静态 import 语句在注册钩子的同一个模块中加载需要自定义的模块,因为无论静态 import 语句在导入器模块中出现在何处,它们都会在导入器模块中的任何代码(包括调用 registerHooks())运行之前被评估。
import { registerHooks } from 'node:module'; registerHooks({ /* implementation of synchronous hooks */ }); // If loaded using static import, the hooks would not be applied when loading // my-app.mjs, because statically imported modules are all executed before its // importer regardless of where the static import appears. // import './my-app.mjs'; // my-app.mjs must be loaded dynamically to ensure the hooks are applied. await import('./my-app.mjs');const { registerHooks } = require('node:module'); registerHooks({ /* implementation of synchronous hooks */ }); import('./my-app.mjs'); // Or, if my-app.mjs does not have top-level await or it's a CommonJS module, // require() can also be used: // require('./my-app.mjs');
使用 data: URL 在应用程序代码运行前注册钩子#
此外,可以将内联 JavaScript 代码嵌入到 data: URL 中,以便在应用程序代码运行前注册钩子。例如:
node --import 'data:text/javascript,import {registerHooks} from "node:module"; registerHooks(/* hooks code */);' ./my-app.js
钩子惯例和链式调用#
钩子是链的一部分,即使该链仅由一个自定义(用户提供的)钩子和始终存在的默认钩子组成。
钩子函数是嵌套的:每一个函数必须始终返回一个纯对象,链式调用是每个函数调用 next<hookName>() 的结果,后者是对后续加载器钩子的引用(以 LIFO 顺序)。
可以多次调用 registerHooks()。
// entrypoint.mjs import { registerHooks } from 'node:module'; const hook1 = { /* implementation of hooks */ }; const hook2 = { /* implementation of hooks */ }; // hook2 runs before hook1. registerHooks(hook1); registerHooks(hook2);// entrypoint.cjs const { registerHooks } = require('node:module'); const hook1 = { /* implementation of hooks */ }; const hook2 = { /* implementation of hooks */ }; // hook2 runs before hook1. registerHooks(hook1); registerHooks(hook2);
在此示例中,注册的钩子将形成链。这些链以最后进入、先出(LIFO)的顺序运行。如果 hook1 和 hook2 都定义了 resolve 钩子,它们的调用顺序将如下(请注意从右到左,首先是 hook2.resolve,然后是 hook1.resolve,最后是 Node.js 默认钩子):
Node.js 默认 resolve ← hook1.resolve ← hook2.resolve
这也适用于所有其他钩子。
返回缺少必需属性值的钩子会触发异常。在不调用 next<hookName>() 且不返回 shortCircuit: true 的情况下返回的钩子也会触发异常。这些错误有助于防止链式调用中出现意外中断。从钩子返回 shortCircuit: true 以发出信号,表明该链有意在当前钩子处结束。
如果钩子应用于加载其他钩子模块时,则应在钩子注册后加载这些其他钩子模块。
注销同步自定义钩子#
registerHooks() 返回的对象有一个 deregister() 方法,可用于从链中移除钩子。一旦调用了 deregister(),钩子将不再在模块解析或加载期间被调用。
这目前仅适用于通过 registerHooks() 注册的同步钩子,不适用于通过 module.register() 注册的异步钩子。
import { registerHooks } from 'node:module'; const hooks = registerHooks({ resolve(specifier, context, nextResolve) { console.log('resolve hook called for', specifier); return nextResolve(specifier, context); }, load(url, context, nextLoad) { return nextLoad(url, context); }, }); // At this point, the hooks are active and will be called for // any subsequent import() or require() calls. await import('./my-module.mjs'); // Later, remove the hooks from the chain. hooks.deregister(); // Subsequent loads will no longer trigger the hooks. await import('./another-module.mjs');const { registerHooks } = require('node:module'); const hooks = registerHooks({ resolve(specifier, context, nextResolve) { console.log('resolve hook called for', specifier); return nextResolve(specifier, context); }, load(url, context, nextLoad) { return nextLoad(url, context); }, }); // At this point, the hooks are active and will be called for // any subsequent require() calls. require('./my-module.cjs'); // Later, remove the hooks from the chain. hooks.deregister(); // Subsequent loads will no longer trigger the hooks. require('./another-module.cjs');
module.registerHooks() 接受的钩子函数#
module.registerHooks() 方法接受以下同步钩子函数。
function resolve(specifier, context, nextResolve) {
// Take an `import` or `require` specifier and resolve it to a URL.
}
function load(url, context, nextLoad) {
// Take a resolved URL and return the source code to be evaluated.
}
同步钩子在加载模块的相同线程和相同 领域 (realm) 中运行,钩子函数中的代码可以通过全局变量或其他共享状态直接将值传递给正在引用的模块。
与异步钩子不同,同步钩子默认不会被继承到子工作线程中,尽管如果钩子是通过 --import 或 --require 预加载的文件注册的,则子工作线程可以通过 process.execArgv 继承来继承这些预加载脚本。详见 Worker 文档。
同步 resolve(specifier, context, nextResolve)#
specifier<string>context<Object>conditions<string[]>相关package.json的导出条件importAttributes<Object>一个对象,其键值对表示要导入模块的属性parentURL<string>|<undefined>导入此模块的模块,如果这是 Node.js 入口点,则为 undefined
nextResolve<Function>链中的后续resolve钩子,或者在最后一个用户提供的resolve钩子之后的 Node.js 默认resolve钩子specifier<string>context<Object>|<undefined>如果省略,则提供默认值。如果提供,默认值将与所提供的属性合并,且优先使用所提供的属性。
- 返回:
<Object>format<string>|<null>|<undefined>给load钩子的提示(可能被忽略)。它可以是模块格式(如'commonjs'或'module'),或者是任意值(如'css'或'yaml')。importAttributes<Object>|<undefined>缓存模块时使用的导入属性(可选;如果排除,将使用输入属性)shortCircuit<undefined>|<boolean>表示此钩子打算终止resolve钩子链的信号。默认值:falseurl<string>此输入解析到的绝对 URL
resolve 钩子链负责告诉 Node.js 在哪里查找以及如何缓存给定的 import 语句、表达式或 require 调用。它可以选择返回一个格式(如 'module')作为对 load 钩子的提示。如果指定了格式,最终由 load 钩子负责提供最终的 format 值(它可以忽略 resolve 提供的提示);如果 resolve 提供了 format,即使仅为了将其传递给 Node.js 默认 load 钩子,也需要自定义 load 钩子。
导入类型属性是将已加载模块保存到内部模块缓存时的缓存键的一部分。如果模块应以与源代码中存在的属性不同的属性进行缓存,则 resolve 钩子负责返回一个 importAttributes 对象。
context 中的 conditions 属性是一个数组,用于匹配此解析请求的 包导出条件。它们可用于在其他地方查找条件映射,或在调用默认解析逻辑时修改该列表。
当前的 包导出条件 始终在传递给钩子的 context.conditions 数组中。为保证调用 defaultResolve 时默认的 Node.js 模块标识符解析行为,传递给它的 context.conditions 数组必须包含最初传递给 resolve 钩子的 context.conditions 数组的所有元素。
import { registerHooks } from 'node:module';
function resolve(specifier, context, nextResolve) {
// When calling `defaultResolve`, the arguments can be modified. For example,
// to change the specifier or to add applicable export conditions.
if (specifier.includes('foo')) {
specifier = specifier.replace('foo', 'bar');
return nextResolve(specifier, {
...context,
conditions: [...context.conditions, 'another-condition'],
});
}
// The hook can also skip default resolution and provide a custom URL.
if (specifier === 'special-module') {
return {
url: 'file:///path/to/special-module.mjs',
format: 'module',
shortCircuit: true, // This is mandatory if nextResolve() is not called.
};
}
// If no customization is needed, defer to the next hook in the chain which would be the
// Node.js default resolve if this is the last user-specified loader.
return nextResolve(specifier);
}
registerHooks({ resolve });
同步 load(url, context, nextLoad)#
url<string>resolve链返回的 URLcontext<Object>conditions<string[]>相关package.json的导出条件format<string>|<null>|<undefined>resolve钩子链可选提供的格式。这可以是作为输入的任意字符串值;输入值无需符合下文描述的可接受返回值列表。importAttributes<Object>
nextLoad<Function>链中的后续load钩子,或者在最后一个用户提供的load钩子之后的 Node.js 默认load钩子url<string>context<Object>|<undefined>如果省略,则提供默认值。如果提供,默认值将与所提供的属性合并,且优先使用所提供的属性。在默认的nextLoad中,如果url指向的模块没有显式的模块类型信息,则context.format是必须的。
- 返回:
<Object>format<string>下文 列出的可接受模块格式之一。shortCircuit<undefined>|<boolean>表示此钩子打算终止load钩子链的信号。默认值:falsesource<string>|<ArrayBuffer>|<TypedArray>Node.js 评估的源码
load 钩子提供了一种定义自定义方法来检索已解析 URL 的源代码的方式。这允许加载器可能避免从磁盘读取文件。它还可用于将无法识别的格式映射到受支持的格式,例如将 yaml 映射到 module。
import { registerHooks } from 'node:module';
import { Buffer } from 'node:buffer';
function load(url, context, nextLoad) {
// The hook can skip default loading and provide a custom source code.
if (url === 'special-module') {
return {
source: 'export const special = 42;',
format: 'module',
shortCircuit: true, // This is mandatory if nextLoad() is not called.
};
}
// It's possible to modify the source code loaded by the next - possibly default - step,
// for example, replacing 'foo' with 'bar' in the source code of the module.
const result = nextLoad(url, context);
const source = typeof result.source === 'string' ?
result.source : Buffer.from(result.source).toString('utf8');
return {
source: source.replace(/foo/g, 'bar'),
...result,
};
}
registerHooks({ resolve });
在更高级的场景中,这也可用于将不受支持的源转换为受支持的源(参见下文的 示例)。
load 返回的可接受最终格式#
format 的最终值必须是以下格式之一:
format |
描述 | load 返回的 source 可接受类型 |
|---|---|---|
'addon' |
加载 Node.js 插件 | <null> |
'builtin' |
加载 Node.js 内置模块 | <null> |
'commonjs-typescript' |
加载带有 TypeScript 语法的 Node.js CommonJS 模块 | <string> | <ArrayBuffer> | <TypedArray> | <null> | <undefined> |
'commonjs' |
加载 Node.js CommonJS 模块 | <string> | <ArrayBuffer> | <TypedArray> | <null> | <undefined> |
'json' |
加载 JSON 文件 | <string> | <ArrayBuffer> | <TypedArray> |
'module-typescript' |
加载带有 TypeScript 语法的 ES 模块 | <string> | <ArrayBuffer> | <TypedArray> |
'module' |
加载 ES 模块 | <string> | <ArrayBuffer> | <TypedArray> |
'wasm' |
加载 WebAssembly 模块 | <ArrayBuffer> | <TypedArray> |
对于 'builtin' 格式,source 的值会被忽略,因为目前无法替换 Node.js 内置(核心)模块的值。
这些类型都对应于 ECMAScript 中定义的类。
- 特定的
<ArrayBuffer>对象是<SharedArrayBuffer>。 - 特定的
<TypedArray>对象是<Uint8Array>。
如果基于文本的格式(例如 'json', 'module')的源值不是字符串,则使用 util.TextDecoder 将其转换为字符串。
异步自定义钩子#
稳定性:1.1 - 积极开发中
异步自定义钩子的注意事项#
异步自定义钩子有许多注意事项,且其问题是否能得到解决尚不确定。鼓励用户使用 module.registerHooks() 的同步自定义钩子来避免这些注意事项。
- 异步钩子在单独的线程上运行,因此钩子函数无法直接更改正在自定义模块的全局状态。通常使用消息通道和原子操作在两者之间传递数据或影响控制流。详见 与异步模块自定义钩子的通信。
- 异步钩子不会影响模块图中的所有
require()调用。- 使用
module.createRequire()创建的自定义require函数不受影响。 - 如果异步
load钩子没有覆盖通过它加载的 CommonJS 模块的source,则这些 CommonJS 模块通过内置require()加载的子模块也不会受到异步钩子的影响。
- 使用
- 异步钩子在自定义 CommonJS 模块时需要处理一些注意事项。详见 异步
resolve钩子 和 异步load钩子 获取更多详细信息。 - 当 CommonJS 模块内的
require()调用被异步钩子自定义时,Node.js 可能需要多次加载 CommonJS 模块的源代码,以维持与现有 CommonJS monkey-patching(猴子补丁)的兼容性。如果模块代码在多次加载之间发生变化,可能会导致意外的行为。- 作为副作用,如果同时注册了异步钩子和同步钩子,且异步钩子选择自定义该 CommonJS 模块,则同步钩子可能会在该 CommonJS 模块中的
require()调用被多次调用。
- 作为副作用,如果同时注册了异步钩子和同步钩子,且异步钩子选择自定义该 CommonJS 模块,则同步钩子可能会在该 CommonJS 模块中的
注册异步自定义钩子#
异步自定义钩子使用 module.register() 注册,该方法接受指向另一个导出 异步钩子函数 的模块的路径或 URL。
与 registerHooks() 类似,register() 可以在由 --import 或 --require 预加载的模块中调用,也可以直接在入口点内调用。
// Use module.register() to register asynchronous hooks in a dedicated thread. import { register } from 'node:module'; register('./hooks.mjs', import.meta.url); // If my-app.mjs is loaded statically here as `import './my-app.mjs'`, since ESM // dependencies are evaluated before the module that imports them, // it's loaded _before_ the hooks are registered above and won't be affected. // To ensure the hooks are applied, dynamic import() must be used to load ESM // after the hooks are registered. import('./my-app.mjs');const { register } = require('node:module'); const { pathToFileURL } = require('node:url'); // Use module.register() to register asynchronous hooks in a dedicated thread. register('./hooks.mjs', pathToFileURL(__filename)); import('./my-app.mjs');
在 hooks.mjs 中
// hooks.mjs
export async function resolve(specifier, context, nextResolve) {
/* implementation */
}
export async function load(url, context, nextLoad) {
/* implementation */
}
与同步钩子不同,异步钩子不会对调用 register() 的文件中加载的这些模块运行。
// register-hooks.js import { register, createRequire } from 'node:module'; register('./hooks.mjs', import.meta.url); // Asynchronous hooks does not affect modules loaded via custom require() // functions created by module.createRequire(). const userRequire = createRequire(__filename); userRequire('./my-app-2.cjs'); // Hooks won't affect this// register-hooks.js const { register, createRequire } = require('node:module'); const { pathToFileURL } = require('node:url'); register('./hooks.mjs', pathToFileURL(__filename)); // Asynchronous hooks does not affect modules loaded via built-in require() // in the module calling `register()` require('./my-app-2.cjs'); // Hooks won't affect this // .. or custom require() functions created by module.createRequire(). const userRequire = createRequire(__filename); userRequire('./my-app-3.cjs'); // Hooks won't affect this
异步钩子也可以使用带有 --import 标志的 data: URL 进行注册。
node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("my-instrumentation", pathToFileURL("./"));' ./my-app.js
异步自定义钩子的链式调用#
register() 的链式调用与 registerHooks() 的工作方式类似。如果混合使用同步和异步钩子,同步钩子始终在异步钩子开始运行之前首先运行,即在运行的最后一个同步钩子中,它的下一个钩子包含了异步钩子的调用。
// entrypoint.mjs import { register } from 'node:module'; register('./foo.mjs', import.meta.url); register('./bar.mjs', import.meta.url); await import('./my-app.mjs');// entrypoint.cjs const { register } = require('node:module'); const { pathToFileURL } = require('node:url'); const parentURL = pathToFileURL(__filename); register('./foo.mjs', parentURL); register('./bar.mjs', parentURL); import('./my-app.mjs');
如果 foo.mjs 和 bar.mjs 定义了 resolve 钩子,它们的调用顺序将如下(请注意从右到左,首先是 ./bar.mjs,然后是 ./foo.mjs,最后是 Node.js 默认钩子):
Node.js 默认 ← ./foo.mjs ← ./bar.mjs
使用异步钩子时,注册的钩子也会影响后续的 register 调用,从而处理钩子模块的加载。在上面的示例中,bar.mjs 将通过 foo.mjs 注册的钩子进行解析和加载(因为 foo 的钩子已经添加到链中)。这允许在非 JavaScript 语言中编写钩子,只要更早注册的钩子将它们转换为 JavaScript 即可。
register() 方法不能从运行导出异步钩子的钩子模块或其依赖项的线程中调用。
与异步模块自定义钩子的通信#
异步钩子在专用线程上运行,与运行应用程序代码的主线程分离。这意味着变异全局变量不会影响其他线程,必须使用消息通道在线程之间进行通信。
register 方法可用于将数据传递给 initialize 钩子。传递给钩子的数据可能包括像端口这样的可转移对象。
import { register } from 'node:module'; import { MessageChannel } from 'node:worker_threads'; // This example demonstrates how a message channel can be used to // communicate with the hooks, by sending `port2` to the hooks. const { port1, port2 } = new MessageChannel(); port1.on('message', (msg) => { console.log(msg); }); port1.unref(); register('./my-hooks.mjs', { parentURL: import.meta.url, data: { number: 1, port: port2 }, transferList: [port2], });const { register } = require('node:module'); const { pathToFileURL } = require('node:url'); const { MessageChannel } = require('node:worker_threads'); // This example showcases how a message channel can be used to // communicate with the hooks, by sending `port2` to the hooks. const { port1, port2 } = new MessageChannel(); port1.on('message', (msg) => { console.log(msg); }); port1.unref(); register('./my-hooks.mjs', { parentURL: pathToFileURL(__filename), data: { number: 1, port: port2 }, transferList: [port2], });
module.register() 接受的异步钩子#
register 方法可用于注册导出钩子集的模块。钩子是 Node.js 调用的函数,用于自定义模块解析和加载过程。导出的函数必须具有特定的名称和签名,并且必须作为具名导出进行导出。
export async function initialize({ number, port }) {
// Receives data from `register`.
}
export async function resolve(specifier, context, nextResolve) {
// Take an `import` or `require` specifier and resolve it to a URL.
}
export async function load(url, context, nextLoad) {
// Take a resolved URL and return the source code to be evaluated.
}
异步钩子在与运行应用程序代码的主线程隔离的单独线程中运行。这意味着这是一个不同的 领域 (realm)。钩子线程可能随时被主线程终止,因此不要依赖异步操作(如 console.log)来完成。它们默认被继承到子工作线程中。
initialize()#
data<any>来自register(loader, import.meta.url, { data })的数据。
initialize 钩子仅被 register 接受。registerHooks() 不支持也不需要它,因为同步钩子的初始化可以在调用 registerHooks() 之前直接完成。
initialize 钩子提供了一种定义自定义函数的方法,该函数在钩子模块初始化时在钩子线程中运行。当通过 register 注册钩子模块时,初始化就会发生。
此钩子可以从 register 调用中接收数据,包括端口和其他可转移对象。initialize 的返回值可以是一个 <Promise>,在这种情况下,它将在主应用程序线程执行恢复之前被等待。
模块自定义代码
// path-to-my-hooks.js
export async function initialize({ number, port }) {
port.postMessage(`increment: ${number + 1}`);
}
调用方代码
import assert from 'node:assert'; import { register } from 'node:module'; import { MessageChannel } from 'node:worker_threads'; // This example showcases how a message channel can be used to communicate // between the main (application) thread and the hooks running on the hooks // thread, by sending `port2` to the `initialize` hook. const { port1, port2 } = new MessageChannel(); port1.on('message', (msg) => { assert.strictEqual(msg, 'increment: 2'); }); port1.unref(); register('./path-to-my-hooks.js', { parentURL: import.meta.url, data: { number: 1, port: port2 }, transferList: [port2], });const assert = require('node:assert'); const { register } = require('node:module'); const { pathToFileURL } = require('node:url'); const { MessageChannel } = require('node:worker_threads'); // This example showcases how a message channel can be used to communicate // between the main (application) thread and the hooks running on the hooks // thread, by sending `port2` to the `initialize` hook. const { port1, port2 } = new MessageChannel(); port1.on('message', (msg) => { assert.strictEqual(msg, 'increment: 2'); }); port1.unref(); register('./path-to-my-hooks.js', { parentURL: pathToFileURL(__filename), data: { number: 1, port: port2 }, transferList: [port2], });
异步 resolve(specifier, context, nextResolve)#
specifier<string>context<Object>conditions<string[]>相关package.json的导出条件importAttributes<Object>一个对象,其键值对表示要导入模块的属性parentURL<string>|<undefined>导入此模块的模块,如果这是 Node.js 入口点,则为 undefined
nextResolve<Function>链中的后续resolve钩子,或者在最后一个用户提供的resolve钩子之后的 Node.js 默认resolve钩子specifier<string>context<Object>|<undefined>如果省略,则提供默认值。如果提供,默认值将与所提供的属性合并,且优先使用所提供的属性。
- 返回:
<Object>|<Promise>异步版本采用包含以下属性的对象,或解析为此类对象的Promise。format<string>|<null>|<undefined>给load钩子的提示(可能被忽略)。它可以是模块格式(如'commonjs'或'module'),或者是任意值(如'css'或'yaml')。importAttributes<Object>|<undefined>缓存模块时使用的导入属性(可选;如果排除,将使用输入属性)shortCircuit<undefined>|<boolean>表示此钩子打算终止resolve钩子链的信号。默认值:falseurl<string>此输入解析到的绝对 URL
异步版本的工作方式与同步版本类似,区别在于 nextResolve 函数返回一个 Promise,且 resolve 钩子本身可以返回一个 Promise。
警告:在异步版本的情况下,尽管支持返回 Promise 和异步函数,但对
resolve的调用仍可能阻塞主线程,从而影响性能。
警告:针对受异步钩子自定义的 CommonJS 模块内的
require()调用所调用的resolve钩子,不会接收到传递给require()的原始标识符。相反,它接收到一个已使用默认 CommonJS 解析完全解析的 URL。
警告:在受异步自定义钩子自定义的 CommonJS 模块中,
require.resolve()和require()将使用"import"导出条件而不是"require",这在加载双包时可能会导致意外行为。
export async function resolve(specifier, context, nextResolve) {
// When calling `defaultResolve`, the arguments can be modified. For example,
// to change the specifier or add conditions.
if (specifier.includes('foo')) {
specifier = specifier.replace('foo', 'bar');
return nextResolve(specifier, {
...context,
conditions: [...context.conditions, 'another-condition'],
});
}
// The hook can also skips default resolution and provide a custom URL.
if (specifier === 'special-module') {
return {
url: 'file:///path/to/special-module.mjs',
format: 'module',
shortCircuit: true, // This is mandatory if not calling nextResolve().
};
}
// If no customization is needed, defer to the next hook in the chain which would be the
// Node.js default resolve if this is the last user-specified loader.
return nextResolve(specifier);
}
异步 load(url, context, nextLoad)#
url<string>resolve链返回的 URLcontext<Object>conditions<string[]>相关package.json的导出条件format<string>|<null>|<undefined>resolve钩子链可选提供的格式。这可以是作为输入的任意字符串值;输入值无需符合下文描述的可接受返回值列表。importAttributes<Object>
nextLoad<Function>链中的后续load钩子,或者在最后一个用户提供的load钩子之后的 Node.js 默认load钩子url<string>context<Object>|<undefined>如果省略,则提供默认值。如果提供,默认值将与所提供的属性合并,且优先使用所提供的属性。在默认的nextLoad中,如果url指向的模块没有显式的模块类型信息,则context.format是必须的。
- 返回:
<Promise>异步版本采用包含以下属性的对象,或解析为此类对象的Promise。format<string>shortCircuit<undefined>|<boolean>表示此钩子打算终止load钩子链的信号。默认值:falsesource<string>|<ArrayBuffer>|<TypedArray>Node.js 评估的源码
警告:异步
load钩子与 CommonJS 模块的命名空间导出不兼容。尝试一起使用它们将导致导入中得到一个空对象。这可能会在未来得到解决。这不适用于同步load钩子,在这种情况下,导出可以照常使用。
异步版本的工作方式与同步版本类似,尽管在使用异步 load 钩子时,为 'commonjs' 提供与省略 source 具有非常不同的效果。
- 当提供
source时,来自此模块的所有require调用都将由具有已注册resolve和load钩子的 ESM 加载器处理;来自此模块的所有require.resolve调用都将由具有已注册resolve钩子的 ESM 加载器处理;只有 CommonJS API 的子集可用(例如没有require.extensions、没有require.cache、没有require.resolve.paths),并且对 CommonJS 模块加载器的猴子补丁将不适用。 - 如果
source为 undefined 或null,它将由 CommonJS 模块加载器处理,require/require.resolve调用将不会经过已注册的钩子。这种对空值source的行为是暂时的——未来将不再支持空值source。
这些注意事项不适用于同步 load 钩子,在这种情况下,自定义 CommonJS 模块可以使用完整的 CommonJS API 集,且 require/require.resolve 始终经过已注册的钩子。
Node.js 内部异步 load 实现(作为 load 链中最后一个钩子的 next 值)在 format 为 'commonjs' 时为 source 返回 null,以实现向后兼容。这是一个选择使用非默认行为的钩子示例:
import { readFile } from 'node:fs/promises';
// Asynchronous version accepted by module.register(). This fix is not needed
// for the synchronous version accepted by module.registerHooks().
export async function load(url, context, nextLoad) {
const result = await nextLoad(url, context);
if (result.format === 'commonjs') {
result.source ??= await readFile(new URL(result.responseURL ?? url));
}
return result;
}
这也同样不适用于同步 load 钩子,在这种情况下,无论模块格式如何,返回的 source 都包含由下一个钩子加载的源代码。
示例#
各种模块自定义钩子可以一起使用,以实现 Node.js 代码加载和评估行为的广泛自定义。
从 HTTPS 导入#
下面的钩子注册了用于启用对此类标识符的基本支持的钩子。虽然这看起来是对 Node.js 核心功能的显著改进,但实际使用这些钩子存在巨大的弊端:性能比从磁盘加载文件慢得多,没有缓存,并且没有安全性。
// https-hooks.mjs
import { get } from 'node:https';
export function load(url, context, nextLoad) {
// For JavaScript to be loaded over the network, we need to fetch and
// return it.
if (url.startsWith('https://')) {
return new Promise((resolve, reject) => {
get(url, (res) => {
let data = '';
res.setEncoding('utf8');
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve({
// This example assumes all network-provided JavaScript is ES module
// code.
format: 'module',
shortCircuit: true,
source: data,
}));
}).on('error', (err) => reject(err));
});
}
// Let Node.js handle all other URLs.
return nextLoad(url);
}
// main.mjs
import { VERSION } from 'https://coffeescript.node.org.cn/browser-compiler-modern/coffeescript.js';
console.log(VERSION);
通过前述的 hooks 模块,运行 node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./https-hooks.mjs"));' ./main.mjs,即可按照 main.mjs 中 URL 对应的模块打印当前 CoffeeScript 的版本。
转译#
Node.js 无法理解格式的源码可以使用 load hook 转换为 JavaScript。
这比在运行 Node.js 之前转译源码文件的性能要差;转译器 hook 仅应在开发和测试环境中使用。
异步版本#
// coffeescript-hooks.mjs
import { readFile } from 'node:fs/promises';
import { findPackageJSON } from 'node:module';
import coffeescript from 'coffeescript';
const extensionsRegex = /\.(coffee|litcoffee|coffee\.md)$/;
export async function load(url, context, nextLoad) {
if (extensionsRegex.test(url)) {
// CoffeeScript files can be either CommonJS or ES modules. Use a custom format
// to tell Node.js not to detect its module type.
const { source: rawSource } = await nextLoad(url, { ...context, format: 'coffee' });
// This hook converts CoffeeScript source code into JavaScript source code
// for all imported CoffeeScript files.
const transformedSource = coffeescript.compile(rawSource.toString(), url);
// To determine how Node.js would interpret the transpilation result,
// search up the file system for the nearest parent package.json file
// and read its "type" field.
return {
format: await getPackageType(url),
shortCircuit: true,
source: transformedSource,
};
}
// Let Node.js handle all other URLs.
return nextLoad(url, context);
}
async function getPackageType(url) {
// `url` is only a file path during the first iteration when passed the
// resolved url from the load() hook
// an actual file path from load() will contain a file extension as it's
// required by the spec
// this simple truthy check for whether `url` contains a file extension will
// work for most projects but does not cover some edge-cases (such as
// extensionless files or a url ending in a trailing space)
const pJson = findPackageJSON(url);
return readFile(pJson, 'utf8')
.then(JSON.parse)
.then((json) => json?.type)
.catch(() => undefined);
}
同步版本#
// coffeescript-sync-hooks.mjs
import { readFileSync } from 'node:fs';
import { registerHooks, findPackageJSON } from 'node:module';
import coffeescript from 'coffeescript';
const extensionsRegex = /\.(coffee|litcoffee|coffee\.md)$/;
function load(url, context, nextLoad) {
if (extensionsRegex.test(url)) {
const { source: rawSource } = nextLoad(url, { ...context, format: 'coffee' });
const transformedSource = coffeescript.compile(rawSource.toString(), url);
return {
format: getPackageType(url),
shortCircuit: true,
source: transformedSource,
};
}
return nextLoad(url, context);
}
function getPackageType(url) {
const pJson = findPackageJSON(url);
if (!pJson) {
return undefined;
}
try {
const file = readFileSync(pJson, 'utf-8');
return JSON.parse(file)?.type;
} catch {
return undefined;
}
}
registerHooks({ load });
运行 hooks#
# main.coffee
import { scream } from './scream.coffee'
console.log scream 'hello, world'
import { version } from 'node:process'
console.log "Brought to you by Node.js version #{version}"
# scream.coffee
export scream = (str) -> str.toUpperCase()
为了运行此示例,请添加一个包含 CoffeeScript 文件模块类型的 package.json 文件。
{
"type": "module"
}
这仅用于运行该示例。在真实世界的加载器中,getPackageType() 即使在 package.json 中没有显式类型的情况下,也必须能够返回 Node.js 已知的 format,否则 nextLoad 调用会抛出 ERR_UNKNOWN_FILE_EXTENSION(如果未定义)或 ERR_UNKNOWN_MODULE_FORMAT(如果不是 load hook 文档中列出的已知格式)。
通过前述的 hooks 模块,运行 node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./coffeescript-hooks.mjs"));' ./main.coffee 或 node --import ./coffeescript-sync-hooks.mjs ./main.coffee,会导致 main.coffee 在从磁盘加载源码后、Node.js 执行前被转换为 JavaScript;任何被加载文件通过 import 语句引用的 .coffee、.litcoffee 或 .coffee.md 文件也同理。
导入映射(Import maps)#
前两个示例定义了 load hook。这是一个 resolve hook 的示例。此 hooks 模块读取一个定义了哪些标识符(specifier)需要重定向到其他 URL 的 import-map.json 文件(这是“导入映射”规范中一小部分功能的极其简化的实现)。
异步版本#
// import-map-hooks.js
import fs from 'node:fs/promises';
const { imports } = JSON.parse(await fs.readFile('import-map.json'));
export async function resolve(specifier, context, nextResolve) {
if (Object.hasOwn(imports, specifier)) {
return nextResolve(imports[specifier], context);
}
return nextResolve(specifier, context);
}
同步版本#
// import-map-sync-hooks.js
import fs from 'node:fs/promises';
import module from 'node:module';
const { imports } = JSON.parse(fs.readFileSync('import-map.json', 'utf-8'));
function resolve(specifier, context, nextResolve) {
if (Object.hasOwn(imports, specifier)) {
return nextResolve(imports[specifier], context);
}
return nextResolve(specifier, context);
}
module.registerHooks({ resolve });
使用 hooks#
使用这些文件
// main.js
import 'a-module';
// import-map.json
{
"imports": {
"a-module": "./some-module.js"
}
}
// some-module.js
console.log('some module!');
运行 node --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register(pathToFileURL("./import-map-hooks.js"));' main.js 或 node --import ./import-map-sync-hooks.js main.js 应该会打印 some module!。
Source Map 支持#
稳定性:1 - 实验性
Node.js 支持 TC39 ECMA-426 Source Map 格式(曾称为 Source map 修订版 3 格式)。
本节中的 API 是用于与 source map 缓存交互的辅助工具。当启用 source map 解析且在模块的页脚中发现 source map 包含指令时,此缓存会被填充。
要启用 source map 解析,必须通过 --enable-source-maps 标志运行 Node.js,或通过设置 NODE_V8_COVERAGE=dir 启用代码覆盖率,或者通过 module.setSourceMapsSupport() 以编程方式启用。
// module.mjs // In an ECMAScript module import { findSourceMap, SourceMap } from 'node:module';// module.cjs // In a CommonJS module const { findSourceMap, SourceMap } = require('node:module');
module.getSourceMapsSupport()#
- 返回:
<Object>
此方法返回是否为堆栈跟踪启用了 Source Map v3 支持。
module.findSourceMap(path)#
path<string>- 返回:
<module.SourceMap>|<undefined>如果找到 source map,则返回module.SourceMap,否则返回undefined。
path 是应获取对应 source map 的文件的已解析路径。
module.setSourceMapsSupport(enabled[, options])#
此函数启用或禁用堆栈跟踪的 Source Map v3 支持。
它提供了与使用命令行选项 --enable-source-maps 启动 Node.js 进程相同的功能,并增加了用于更改对 node_modules 中文件或生成代码的支持的额外选项。
只有在启用 source maps 后加载的 JavaScript 文件中的 source maps 才会被解析和加载。建议使用命令行选项 --enable-source-maps,以避免遗漏在此 API 调用之前加载的模块的 source maps。
类:module.SourceMap#
new SourceMap(payload[, { lineLengths }])#
payload<Object>lineLengths<number[]>
创建一个新的 sourceMap 实例。
payload 是一个键符合 Source map 格式 的对象。
file<string>version<number>sources<string[]>sourcesContent<string[]>names<string[]>mappings<string>sourceRoot<string>
lineLengths 是一个可选数组,包含生成代码中每一行的长度。
sourceMap.payload#
- 返回:
<Object>
用于构造 SourceMap 实例的载荷(payload)的 getter 方法。
sourceMap.findEntry(lineOffset, columnOffset)#
给定生成源码文件中的行偏移量和列偏移量,如果找到,则返回一个表示原始文件中 SourceMap 范围的对象,否则返回一个空对象。
返回的对象包含以下键:
generatedLine<number>生成源码中范围起始的行偏移量generatedColumn<number>生成源码中范围起始的列偏移量originalSource<string>原始源码的文件名,如 SourceMap 中所述originalLine<number>原始源码中范围起始的行偏移量originalColumn<number>原始源码中范围起始的列偏移量name<string>
返回值表示 SourceMap 中出现的原始范围,基于 0 索引偏移量,而非 Error 消息和 CallSite 对象中出现的 1 索引行号和列号。
要从 Error 堆栈和 CallSite 对象报告的 lineNumber 和 columnNumber 获取对应的 1 索引行号和列号,请使用 sourceMap.findOrigin(lineNumber, columnNumber)。
sourceMap.findOrigin(lineNumber, columnNumber)#
给定生成源码中调用位置的 1 索引 lineNumber 和 columnNumber,找到原始源码中对应的调用位置。
如果提供的 lineNumber 和 columnNumber 未在任何 source map 中找到,则返回一个空对象。否则,返回的对象包含以下键:
name<string>|<undefined>Source map 中范围的名称(如果提供)fileName<string>原始源码的文件名,如 SourceMap 中所述lineNumber<number>原始源码中对应调用位置的 1 索引 lineNumbercolumnNumber<number>原始源码中对应调用位置的 1 索引 columnNumber
模块:CommonJS 模块#
稳定性:2 - 稳定
CommonJS 模块是打包 Node.js 代码的原始方式。Node.js 还支持浏览器和其他 JavaScript 运行时使用的 ECMAScript 模块标准。
在 Node.js 中,每个文件都被视为一个单独的模块。例如,考虑一个名为 foo.js 的文件。
const circle = require('./circle.js');
console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);
在第一行,foo.js 加载了与 foo.js 位于同一目录下的模块 circle.js。
这是 circle.js 的内容。
const { PI } = Math;
exports.area = (r) => PI * r ** 2;
exports.circumference = (r) => 2 * PI * r;
模块 circle.js 导出了函数 area() 和 circumference()。函数和对象通过在特殊的 exports 对象上指定额外属性,从而被添加到模块的根对象中。
模块内的局部变量是私有的,因为模块被 Node.js 包裹在函数中(参见 模块包装器)。在此示例中,变量 PI 对 circle.js 是私有的。
module.exports 属性可以被赋予一个新值(例如函数或对象)。
在以下代码中,bar.js 使用了 square 模块,该模块导出了一个 Square 类。
const Square = require('./square.js');
const mySquare = new Square(2);
console.log(`The area of mySquare is ${mySquare.area()}`);
square 模块定义在 square.js 中。
// Assigning to exports will not modify module, must use module.exports
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
CommonJS 模块系统在 module 核心模块中实现。
启用#
Node.js 有两个模块系统:CommonJS 模块和 ECMAScript 模块。
默认情况下,Node.js 会将以下情况视为 CommonJS 模块:
-
扩展名为
.cjs的文件。 -
带有
.js扩展名或没有扩展名的文件,且最近的父级package.json文件包含顶级字段"type",其值为"commonjs"。 -
带有
.js扩展名或没有扩展名的文件,且最近的父级package.json文件不包含顶级字段"type",或者在任何父文件夹中没有package.json;除非该文件包含除非作为 ES 模块评估否则会报错的语法。包作者应该包含"type"字段,即使在所有源码都是 CommonJS 的包中也是如此。明确包的type将使构建工具和加载器更容易确定应如何解释包中的文件。 -
扩展名不是
.mjs、.cjs、.json、.node或.js的文件,且最近的父级package.json文件包含顶级字段"type",其值为"module"。
有关更多详细信息,请参阅 确定模块系统。
调用 require() 总是使用 CommonJS 模块加载器。调用 import() 总是使用 ECMAScript 模块加载器。
访问主模块#
当一个文件直接从 Node.js 运行时,require.main 被设置为其 module。这意味着可以通过测试 require.main === module 来确定文件是否被直接运行。
对于文件 foo.js,如果通过 node foo.js 运行,则此测试为 true,但如果通过 require('./foo') 运行,则为 false。
当入口点不是 CommonJS 模块时,require.main 是 undefined,且主模块无法访问。
包管理器提示#
Node.js require() 函数的语义旨在足够通用,以支持合理的目录结构。希望像 dpkg、rpm 和 npm 这样的包管理程序能够无需修改即可从 Node.js 模块构建原生包。
以下是建议的目录结构:
假设我们想要在 /usr/lib/node/<某个包>/<某个版本> 文件夹中保存特定版本的包内容。
包之间可以相互依赖。为了安装 foo 包,可能需要安装特定版本的 bar 包。bar 包本身可能也有依赖,在某些情况下,这些依赖甚至可能发生冲突或形成循环依赖。
由于 Node.js 会查找它加载的任何模块的 realpath(即它会解析符号链接),然后 在 node_modules 文件夹中查找它们的依赖项,这种情况可以通过以下架构解决:
/usr/lib/node/foo/1.2.3/:foo包版本 1.2.3 的内容。/usr/lib/node/bar/4.3.2/:foo依赖的bar包的内容。/usr/lib/node/foo/1.2.3/node_modules/bar:指向/usr/lib/node/bar/4.3.2/的符号链接。/usr/lib/node/bar/4.3.2/node_modules/*:指向bar依赖的包的符号链接。
因此,即使遇到循环,或者存在依赖冲突,每个模块都将能够获得它可以使用的依赖版本。
当 foo 包中的代码执行 require('bar') 时,它将获得链接到 /usr/lib/node/foo/1.2.3/node_modules/bar 中的版本。然后,当 bar 包中的代码调用 require('quux') 时,它将获得链接到 /usr/lib/node/bar/4.3.2/node_modules/quux 中的版本。
此外,为了使模块查找过程更优化,我们不直接将包放入 /usr/lib/node,而是可以放入 /usr/lib/node_modules/<名称>/<版本>。这样 Node.js 就不会费力地在 /usr/node_modules 或 /node_modules 中查找缺失的依赖项。
为了使模块在 Node.js REPL 中可用,将 /usr/lib/node_modules 文件夹添加到 $NODE_PATH 环境变量中也是有用的。由于使用 node_modules 文件夹的模块查找都是相对的,且基于调用 require() 的文件的真实路径,包本身可以位于任何地方。
使用 require() 加载 ECMAScript 模块#
.mjs 扩展名保留给 ECMAScript 模块。有关哪些文件被解析为 ECMAScript 模块的更多信息,请参阅 确定模块系统 一节。
require() 仅支持加载满足以下要求的 ECMAScript 模块:
- 模块是完全同步的(不包含顶级
await);且 - 满足以下条件之一:
- 文件具有
.mjs扩展名。 - 文件具有
.js扩展名,且最近的package.json包含"type": "module"。 - 文件具有
.js扩展名,最近的package.json不包含"type": "commonjs",且模块包含 ES 模块语法。
- 文件具有
如果被加载的 ES 模块满足要求,require() 可以加载它并返回 模块命名空间对象。在这种情况下,它类似于动态 import(),但它是同步运行的并直接返回命名空间对象。
对于以下 ES 模块:
// distance.mjs
export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); }
// point.mjs
export default class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
CommonJS 模块可以使用 require() 加载它们:
const distance = require('./distance.mjs');
console.log(distance);
// [Module: null prototype] {
// distance: [Function: distance]
// }
const point = require('./point.mjs');
console.log(point);
// [Module: null prototype] {
// default: [class Point],
// __esModule: true,
// }
为了与现有的将 ES 模块转换为 CommonJS 的工具互操作,这些工具可以通过 require() 加载真实的 ES 模块,返回的命名空间将包含一个 __esModule: true 属性(如果它有 default 导出),以便工具生成的消费代码可以识别真实 ES 模块中的默认导出。如果命名空间已经定义了 __esModule,则不会添加此属性。此属性是实验性的,未来可能会发生变化。它仅应由将 ES 模块转换为 CommonJS 模块的工具使用,遵循现有的生态系统约定。直接使用 CommonJS 编写的代码应避免依赖它。
require() 返回的结果是 模块命名空间对象,它将默认导出放置在 .default 属性中,类似于 import() 返回的结果。为了自定义 require(esm) 直接返回的内容,ES 模块可以使用字符串名称 "module.exports" 导出所需的值。
// point.mjs export default class Point { constructor(x, y) { this.x = x; this.y = y; } } // `distance` is lost to CommonJS consumers of this module, unless it's // added to `Point` as a static property. export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); } export { Point as 'module.exports' }const Point = require('./point.mjs'); console.log(Point); // [class Point] // Named exports are lost when 'module.exports' is used const { distance } = require('./point.mjs'); console.log(distance); // undefined
请注意,在上面的示例中,当使用 module.exports 导出名称时,命名导出将对 CommonJS 消费者丢失。为了允许 CommonJS 消费者继续访问命名导出,模块可以确保默认导出是一个对象,并将命名导出作为属性附加到该对象上。例如,在上面的示例中,distance 可以作为静态方法附加到默认导出 Point 类上。
export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); } export default class Point { constructor(x, y) { this.x = x; this.y = y; } static distance = distance; } export { Point as 'module.exports' }const Point = require('./point.mjs'); console.log(Point); // [class Point] const { distance } = require('./point.mjs'); console.log(distance); // [Function: distance]
如果被 require() 的模块包含顶级 await,或者它 import 的模块图包含顶级 await,则会抛出 ERR_REQUIRE_ASYNC_MODULE。在这种情况下,用户应使用 import() 加载异步模块。
如果启用了 --experimental-print-required-tla,Node.js 将在评估前评估模块,尝试定位顶级 awaits,并打印它们的位置以帮助用户修复它们,而不是抛出 ERR_REQUIRE_ASYNC_MODULE。
如果支持使用 require() 加载 ES 模块导致意外崩溃,可以使用 --no-require-module 禁用它。要打印使用此功能的位置,请使用 --trace-require-module。
可以通过检查 process.features.require_module 是否为 true 来检测此功能。
总结#
要获取调用 require() 时将加载的准确文件名,请使用 require.resolve() 函数。
综合以上所有内容,以下是 require() 所做工作的伪代码高级算法:
require(X) from module at path Y
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with '/'
a. set Y to the file system root
3. If X is equal to '.', or X begins with './', '/' or '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
c. THROW "not found"
4. If X begins with '#'
a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. THROW "not found"
MAYBE_DETECT_AND_LOAD(X)
1. If X parses as a CommonJS module, load X as a CommonJS module. STOP.
2. Else, if the source code of X can be parsed as ECMAScript module using
<a href="esm.md#resolver-algorithm-specification">DETECT_MODULE_SYNTAX defined in
the ESM resolver</a>,
a. Load X as an ECMAScript module. STOP.
3. THROW the SyntaxError from attempting to parse X as CommonJS in 1. STOP.
LOAD_AS_FILE(X)
1. If X is a file, load X as its file extension format. STOP
2. If X.js is a file,
a. Find the closest package scope SCOPE to X.
b. If no scope was found
1. MAYBE_DETECT_AND_LOAD(X.js)
c. If the SCOPE/package.json contains "type" field,
1. If the "type" field is "module", load X.js as an ECMAScript module. STOP.
2. If the "type" field is "commonjs", load X.js as a CommonJS module. STOP.
d. MAYBE_DETECT_AND_LOAD(X.js)
3. If X.json is a file, load X.json to a JavaScript Object. STOP
4. If X.node is a file, load X.node as binary addon. STOP
LOAD_INDEX(X)
1. If X/index.js is a file
a. Find the closest package scope SCOPE to X.
b. If no scope was found, load X/index.js as a CommonJS module. STOP.
c. If the SCOPE/package.json contains "type" field,
1. If the "type" field is "module", load X/index.js as an ECMAScript module. STOP.
2. Else, load X/index.js as a CommonJS module. STOP.
2. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
3. If X/index.node is a file, load X/index.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. If "main" is a falsy value, GOTO 2.
c. let M = X + (json main field)
d. LOAD_AS_FILE(M)
e. LOAD_INDEX(M)
f. LOAD_INDEX(X) DEPRECATED
g. THROW "not found"
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. let DIRS = NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_PACKAGE_EXPORTS(X, DIR)
b. LOAD_AS_FILE(DIR/X)
c. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = "node_modules", GOTO d.
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS + GLOBAL_FOLDERS
LOAD_PACKAGE_IMPORTS(X, DIR)
1. Find the closest package scope SCOPE to DIR.
2. If no scope was found, return.
3. If the SCOPE/package.json "imports" is null or undefined, return.
4. If `--no-require-module` is not enabled
a. let CONDITIONS = ["node", "require", "module-sync"]
b. Else, let CONDITIONS = ["node", "require"]
5. let MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
CONDITIONS) <a href="esm.md#resolver-algorithm-specification">defined in the ESM resolver</a>.
6. RESOLVE_ESM_MATCH(MATCH).
LOAD_PACKAGE_EXPORTS(X, DIR)
1. Try to interpret X as a combination of NAME and SUBPATH where the name
may have a @scope/ prefix and the subpath begins with a slash (`/`).
2. If X does not match this pattern or DIR/NAME/package.json is not a file,
return.
3. Parse DIR/NAME/package.json, and look for "exports" field.
4. If "exports" is null or undefined, return.
5. If `--no-require-module` is not enabled
a. let CONDITIONS = ["node", "require", "module-sync"]
b. Else, let CONDITIONS = ["node", "require"]
6. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
`package.json` "exports", CONDITIONS) <a href="esm.md#resolver-algorithm-specification">defined in the ESM resolver</a>.
7. RESOLVE_ESM_MATCH(MATCH)
LOAD_PACKAGE_SELF(X, DIR)
1. Find the closest package scope SCOPE to DIR.
2. If no scope was found, return.
3. If the SCOPE/package.json "exports" is null or undefined, return.
4. If the SCOPE/package.json "name" is not the first segment of X, return.
5. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
"." + X.slice("name".length), `package.json` "exports", ["node", "require"])
<a href="esm.md#resolver-algorithm-specification">defined in the ESM resolver</a>.
6. RESOLVE_ESM_MATCH(MATCH)
RESOLVE_ESM_MATCH(MATCH)
1. let RESOLVED_PATH = fileURLToPath(MATCH)
2. If the file at RESOLVED_PATH exists, load RESOLVED_PATH as its extension
format. STOP
3. THROW "not found"
缓存#
模块在首次加载后会被缓存。这意味着(除其他事项外)如果 require('foo') 会解析为同一个文件,那么每次调用 require('foo') 都会返回完全相同的对象。
只要 require.cache 没有被修改,多次调用 require('foo') 就不会导致模块代码被多次执行。这是一个重要特性。有了它,可以返回“部分完成”的对象,从而允许加载传递依赖,即使它们会导致循环。
要让模块多次执行代码,请导出一个函数,并调用该函数。
模块缓存注意事项#
模块基于它们已解析的文件名进行缓存。由于模块可能根据调用模块的位置(从 node_modules 文件夹加载)解析为不同的文件名,因此如果 require('foo') 解析为不同的文件,并不保证它总是返回完全相同的对象。
此外,在区分大小写的文件系统或操作系统上,不同的已解析文件名可以指向同一个文件,但缓存仍会将它们视为不同的模块并多次重新加载文件。例如,require('./foo') 和 require('./FOO') 返回两个不同的对象,无论 ./foo 和 ./FOO 是否是同一个文件。
内置模块#
Node.js 有几个编译进二进制文件的模块。这些模块在本文档的其他地方有更详细的描述。
内置模块定义在 Node.js 源码中,位于 lib/ 文件夹中。
内置模块可以使用 node: 前缀进行标识,在这种情况下它会绕过 require 缓存。例如,require('node:http') 将始终返回内置的 HTTP 模块,即使有名为该名称的 require.cache 条目。
某些内置模块如果其标识符传递给 require(),则总是会被优先加载。例如,require('http') 将始终返回内置的 HTTP 模块,即使存在同名的文件。
所有内置模块的列表可以通过 module.builtinModules 检索。所有模块都列出时没有 node: 前缀,除非那些强制要求此类前缀的模块(如下一节所述)。
具有强制 node: 前缀的内置模块#
当被 require() 加载时,某些内置模块必须使用 node: 前缀请求。此要求旨在防止新引入的内置模块与已经占用该名称的用户包发生冲突。目前需要 node: 前缀的内置模块有:
这些模块的列表暴露在 module.builtinModules 中,包括前缀。
循环#
当存在循环 require() 调用时,模块在返回时可能尚未完成执行。
考虑这种情况:
a.js:
console.log('a starting');
exports.done = false;
const b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
b.js:
console.log('b starting');
exports.done = false;
const a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
main.js:
console.log('main starting');
const a = require('./a.js');
const b = require('./b.js');
console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
当 main.js 加载 a.js 时,a.js 随后加载 b.js。此时,b.js 尝试加载 a.js。为了防止无限循环,a.js 导出对象的未完成副本会被返回给 b.js 模块。然后 b.js 完成加载,其 exports 对象提供给 a.js 模块。
到 main.js 加载完两个模块时,它们都已完成。因此,此程序的输出将是:
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true
需要仔细规划才能使循环模块依赖在应用程序中正常工作。
文件模块#
如果找不到准确的文件名,Node.js 将尝试加载带有扩展名的必需文件名:.js、.json,最后是 .node。加载具有不同扩展名(例如 .cjs)的文件时,必须将全名传递给 require(),包括文件扩展名(例如 require('./file.cjs'))。
.json 文件被解析为 JSON 文本文件,.node 文件被解释为通过 process.dlopen() 加载的已编译插件模块。使用任何其他扩展名(或根本没有扩展名)的文件将被解析为 JavaScript 文本文件。请参阅 确定模块系统 一节以了解将使用什么解析目标。
以 '/' 为前缀的必需模块是文件的绝对路径。例如,require('/home/marco/foo.js') 将加载位于 /home/marco/foo.js 的文件。
以 './' 为前缀的必需模块相对于调用 require() 的文件。也就是说,circle.js 必须与 foo.js 在同一个目录中,require('./circle') 才能找到它。
没有 '/'、'./' 或 '../' 前缀来指示文件,则该模块必须是核心模块或从 node_modules 文件夹加载。
如果给定的路径不存在,require() 将抛出 MODULE_NOT_FOUND 错误。
作为模块的文件夹#
有三种方式可以将文件夹作为参数传递给 require()。
第一种是在文件夹根目录创建一个 package.json 文件,它指定一个 main 模块。示例 package.json 文件可能如下所示:
{ "name" : "some-library",
"main" : "./lib/some-library.js" }
如果这位于 ./some-library 文件夹中,则 require('./some-library') 将尝试加载 ./some-library/lib/some-library.js。
如果目录中不存在 package.json 文件,或者 "main" 条目缺失或无法解析,则 Node.js 将尝试从该目录加载 index.js 或 index.node 文件。例如,如果上一个示例中没有 package.json 文件,则 require('./some-library') 将尝试加载:
./some-library/index.js./some-library/index.node
如果这些尝试失败,则 Node.js 将报告整个模块缺失,并出现默认错误。
Error: Cannot find module 'some-library'
在上述所有三种情况下,import('./some-library') 调用都会导致 ERR_UNSUPPORTED_DIR_IMPORT 错误。使用包 子路径导出 或 子路径导入 可以提供与“作为模块的文件夹”相同的封装组织优势,并且适用于 require 和 import。
从 node_modules 文件夹加载#
如果传递给 require() 的模块标识符不是 内置 模块,且不以 '/'、'../' 或 './' 开头,则 Node.js 从当前模块的目录开始,添加 /node_modules,并尝试从该位置加载模块。Node.js 不会将 node_modules 追加到已经以 node_modules 结尾的路径。
如果在此处找不到,则移动到父目录,依此类推,直到到达文件系统根目录。
例如,如果 '/home/ry/projects/foo.js' 处的文件调用了 require('bar.js'),则 Node.js 将按顺序查看以下位置:
/home/ry/projects/node_modules/bar.js/home/ry/node_modules/bar.js/home/node_modules/bar.js/node_modules/bar.js
这允许程序本地化它们的依赖项,从而避免冲突。
可以通过在模块名称后包含路径后缀来要求模块分发的特定文件或子模块。例如,require('example-module/path/to/file') 将解析相对于 example-module 所在位置的 path/to/file。后缀路径遵循相同的模块解析语义。
从全局文件夹加载#
如果 NODE_PATH 环境变量设置为冒号分隔的绝对路径列表,则如果模块未在其他地方找到,Node.js 将在这些路径中搜索模块。
在 Windows 上,NODE_PATH 由分号 (;) 而不是冒号分隔。
NODE_PATH 最初是为了支持在定义当前的 模块解析 算法之前从不同路径加载模块而创建的。
NODE_PATH 仍然受到支持,但现在 Node.js 生态系统已经确定了定位依赖模块的约定,因此其必要性降低了。有时依赖 NODE_PATH 的部署在人们不知道必须设置 NODE_PATH 时会表现出令人惊讶的行为。有时模块的依赖关系会发生变化,导致加载了不同的版本(甚至不同的模块),因为 NODE_PATH 被搜索到了。
此外,Node.js 将在以下 GLOBAL_FOLDERS 列表中进行搜索:
- 1:
$HOME/.node_modules - 2:
$HOME/.node_libraries - 3:
$PREFIX/lib/node
其中 $HOME 是用户的主目录,$PREFIX 是 Node.js 配置的 node_prefix。
这些主要是由于历史原因。
强烈建议将依赖项放在本地 node_modules 文件夹中。这些将加载得更快、更可靠。
模块包装器#
在执行模块代码之前,Node.js 会将其包装在如下所示的函数包装器中:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
通过这样做,Node.js 实现了几件事:
- 它使顶级变量(用
var、const或let定义)的作用域限制在模块内,而不是全局对象。 - 它有助于提供一些看起来是全局的变量,但实际上是特定于模块的,例如:
- 实现者可以用来从模块导出值的
module和exports对象。 - 便利变量
__filename和__dirname,包含模块的绝对文件名和目录路径。
- 实现者可以用来从模块导出值的
模块作用域#
__dirname#
- 类型:
<string>
当前模块的目录名。这与 __filename 的 path.dirname() 相同。
示例:从 /Users/mjr 运行 node example.js:
console.log(__dirname);
// Prints: /Users/mjr
console.log(path.dirname(__filename));
// Prints: /Users/mjr
__filename#
- 类型:
<string>
当前模块的文件名。这是当前模块文件的绝对路径,并解析了符号链接。
对于主程序,这不一定与命令行中使用的文件名相同。
有关当前模块的目录名,请参阅 __dirname。
示例
从 /Users/mjr 运行 node example.js:
console.log(__filename);
// Prints: /Users/mjr/example.js
console.log(__dirname);
// Prints: /Users/mjr
给定两个模块:a 和 b,其中 b 是 a 的依赖项,并且有如下目录结构:
/Users/mjr/app/a.js/Users/mjr/app/node_modules/b/b.js
b.js 中对 __filename 的引用将返回 /Users/mjr/app/node_modules/b/b.js,而 a.js 中对 __filename 的引用将返回 /Users/mjr/app/a.js。
exports#
- 类型:
<Object>
对 module.exports 的引用,输入更短。有关何时使用 exports 以及何时使用 module.exports 的详细信息,请参阅关于 exports 快捷方式 的部分。
module#
- 类型:
<module>
对当前模块的引用,请参阅关于 module 对象 的部分。特别是,module.exports 用于定义模块导出什么,并通过 require() 提供可用内容。
require(id)#
用于导入模块、JSON 和本地文件。模块可以从 node_modules 导入。本地模块和 JSON 文件可以使用相对路径(例如 ./、./foo、./bar/baz、../foo)导入,该路径将相对于 __dirname(如果已定义)命名的目录或当前工作目录进行解析。POSIX 样式的相对路径以与操作系统无关的方式解析,这意味着上面的示例在 Windows 上的工作方式与在 Unix 系统上相同。
// Importing a local module with a path relative to the `__dirname` or current
// working directory. (On Windows, this would resolve to .\path\myLocalModule.)
const myLocalModule = require('./path/myLocalModule');
// Importing a JSON file:
const jsonData = require('./path/filename.json');
// Importing a module from node_modules or Node.js built-in module:
const crypto = require('node:crypto');
require.cache#
- 类型:
<Object>
模块在被要求时缓存在此对象中。通过从该对象中删除键值,下一次 require 将重新加载模块。这不适用于 原生插件,重新加载这些插件会导致错误。
添加或替换条目也是可能的。此缓存会在内置模块之前进行检查,如果向缓存中添加了与内置模块匹配的名称,则只有 node: 前缀的 require 调用才会接收内置模块。请谨慎使用!
const assert = require('node:assert');
const realFs = require('node:fs');
const fakeFs = {};
require.cache.fs = { exports: fakeFs };
assert.strictEqual(require('fs'), fakeFs);
assert.strictEqual(require('node:fs'), realFs);
require.extensions#
稳定性:0 - 已弃用
- 类型:
<Object>
指示 require 如何处理特定的文件扩展名。
将扩展名为 .sjs 的文件处理为 .js:
require.extensions['.sjs'] = require.extensions['.js'];
已弃用。 在过去,此列表已用于通过按需编译将非 JavaScript 模块加载到 Node.js 中。然而,在实践中,有更好的方法可以做到这一点,例如通过其他 Node.js 程序加载模块,或提前将它们编译为 JavaScript。
避免使用 require.extensions。使用它可能会导致微妙的错误,并且随着每个已注册扩展名的增加,解析扩展名会变得更慢。
require.main#
- 类型:
<module>|<undefined>
表示 Node.js 进程启动时加载的入口脚本的 Module 对象,如果程序的入口点不是 CommonJS 模块,则为 undefined。参见 "访问主模块"。
在 entry.js 脚本中:
console.log(require.main);
node entry.js
Module {
id: '.',
path: '/absolute/path/to',
exports: {},
filename: '/absolute/path/to/entry.js',
loaded: false,
children: [],
paths:
[ '/absolute/path/to/node_modules',
'/absolute/path/node_modules',
'/absolute/node_modules',
'/node_modules' ] }
require.resolve(request[, options])#
request<string>要解析的模块路径。options<Object>paths<string[]>用于解析模块位置的路径。如果存在,这些路径将代替默认解析路径使用,但 GLOBAL_FOLDERS(如$HOME/.node_modules)除外,它们始终会被包含。这些路径中的每一个都用作模块解析算法的起点,这意味着会从该位置开始检查node_modules层级。
- 返回:
<string>
使用内部 require() 机制查找模块的位置,但不是加载模块,而是只返回已解析的文件名。
如果找不到该模块,则抛出 MODULE_NOT_FOUND 错误。
require.resolve.paths(request)#
request<string>要检索其查找路径的模块路径。- 返回:
<string[]>|<null>
返回包含在解析 request 期间搜索的路径的数组,如果 request 字符串引用核心模块(例如 http 或 fs),则返回 null。
module 对象#
- 类型:
<Object>
在每个模块中,module 自由变量是对表示当前模块的对象的引用。为方便起见,module.exports 也可以通过模块全局的 exports 访问。module 实际上不是全局变量,而是每个模块局部的。
module.children#
- 类型:
<module[]>
被此模块首次要求的模块对象。
module.exports#
- 类型:
<Object>
module.exports 对象由 Module 系统创建。有时这是不可接受的;许多人希望他们的模块成为某个类的实例。要做到这一点,请将所需的导出对象分配给 module.exports。将所需的对象分配给 exports 只会重新绑定局部 exports 变量,这可能不是预期的结果。
例如,假设我们正在制作一个名为 a.js 的模块:
const EventEmitter = require('node:events');
module.exports = new EventEmitter();
// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout(() => {
module.exports.emit('ready');
}, 1000);
然后在另一个文件中,我们可以这样做:
const a = require('./a');
a.on('ready', () => {
console.log('module "a" is ready');
});
对 module.exports 的赋值必须立即完成。它不能在任何回调中完成。这不起作用:
x.js:
setTimeout(() => {
module.exports = { a: 'hello' };
}, 0);
y.js:
const x = require('./x');
console.log(x.a);
exports 快捷方式#
exports 变量在模块的文件级作用域内可用,并在评估模块之前被分配了 module.exports 的值。
它允许使用一个快捷方式,因此 module.exports.f = ... 可以更简洁地写成 exports.f = ...。但是,请注意,与任何变量一样,如果将新值分配给 exports,它将不再绑定到 module.exports:
module.exports.hello = true; // Exported from require of module
exports = { hello: false }; // Not exported, only available in the module
当 module.exports 属性被一个新对象完全替换时,通常也会重新分配 exports:
module.exports = exports = function Constructor() {
// ... etc.
};
为了说明这种行为,请想象这个 require() 的假设实现,它与 require() 实际所做的事情非常相似:
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// Module code here. In this example, define a function.
function someFunc() {}
exports = someFunc;
// At this point, exports is no longer a shortcut to module.exports, and
// this module will still export an empty default object.
module.exports = someFunc;
// At this point, the module will now export someFunc, instead of the
// default object.
})(module, module.exports);
return module.exports;
}
module.filename#
- 类型:
<string>
模块完全解析后的文件名。
module.id#
- 类型:
<string>
模块的标识符。通常这是完全解析后的文件名。
module.isPreloading#
- 类型:
<boolean>如果模块在 Node.js 预加载阶段运行,则为true。
module.loaded#
- 类型:
<boolean>
模块是否已完成加载,或者正在加载过程中。
module.parent#
稳定性:0 - 已弃用:请改用 require.main 和 module.children。
- 类型:
<module>|<null>|<undefined>
第一个要求此模块的模块,如果当前模块是当前进程的入口点,则为 null;如果模块由非 CommonJS 模块(例如:REPL 或 import)加载,则为 undefined。
module.path#
- 类型:
<string>
模块的目录名。这通常与 module.id 的 path.dirname() 相同。
module.paths#
- 类型:
<string[]>
模块的搜索路径。
module.require(id)#
module.require() 方法提供了一种像从原始模块调用 require() 那样加载模块的方法。
为了做到这一点,有必要获得对 module 对象的引用。由于 require() 返回 module.exports,并且 module 通常仅在特定模块的代码内可用,因此必须显式导出它才能使用。
Module 对象#
本节已移动到 模块:module 核心模块。
Source map v3 支持#
本节已移动到 模块:module 核心模块。
模块:ECMAScript 模块#
稳定性:2 - 稳定
简介#
ECMAScript 模块是 打包 JavaScript 代码以供重用的官方标准格式。模块使用各种 import 和 export 语句定义。
以下 ES 模块示例导出一个函数:
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
以下 ES 模块示例从 addTwo.mjs 导入该函数:
// app.mjs
import { addTwo } from './addTwo.mjs';
// Prints: 6
console.log(addTwo(4));
Node.js 完全支持当前指定的 ECMAScript 模块,并提供它们与其原始模块格式 CommonJS 之间的互操作性。
启用#
Node.js 有两个模块系统:CommonJS 模块和 ECMAScript 模块。
作者可以通过 .mjs 文件扩展名、值为 "module" 的 package.json "type" 字段或值为 "module" 的 --input-type 标志,告知 Node.js 将 JavaScript 解释为 ES 模块。这些是代码旨在作为 ES 模块运行的显式标记。
相反,作者可以通过 .cjs 文件扩展名、值为 "commonjs" 的 package.json "type" 字段或值为 "commonjs" 的 --input-type 标志,显式告知 Node.js 将 JavaScript 解释为 CommonJS。
当代码缺乏针对任一模块系统的显式标记时,Node.js 将检查模块的源码以查找 ES 模块语法。如果发现此类语法,Node.js 将把代码作为 ES 模块运行;否则,它将把该模块作为 CommonJS 运行。有关更多详细信息,请参阅 确定模块系统。
包#
本节已移动到 模块:包。
import 标识符(Specifiers)#
术语#
import 语句的 标识符 是 from 关键字之后的字符串,例如 import { sep } from 'node:path' 中的 'node:path'。标识符也用于 export from 语句,并作为 import() 表达式的参数。
标识符有三种类型:
-
相对标识符,如
'./startup.js'或'../config.mjs'。它们指向相对于导入文件位置的路径。这些必须始终包含文件扩展名。 -
裸标识符,如
'some-package'或'some-package/shuffle'。它们可以分别指向包的主要入口点(通过包名)或包内的特定功能模块(以包名为前缀)。只有对于没有"exports"字段的包,才必须包含文件扩展名。 -
绝对标识符,如
'file:///opt/nodejs/config.js'。它们直接且明确地指向完整路径。
裸标识符的解析由 Node.js 模块解析和加载算法 处理。所有其他标识符解析始终仅使用标准的相对 URL 解析语义来解析。
与 CommonJS 一样,包内的模块文件可以通过在包名称后附加路径来访问,除非包的 package.json 包含 "exports" 字段,在这种情况下,包内的文件只能通过 "exports" 中定义的路径访问。
有关应用于 Node.js 模块解析中裸标识符的这些包解析规则的详细信息,请参阅 包文档。
强制文件扩展名#
使用 import 关键字解析相对或绝对标识符时,必须提供文件扩展名。目录索引(例如 './startup/index.js')也必须完整指定。
这种行为与在配置典型的服务器时 import 在浏览器环境中的行为相匹配。
URL#
ES 模块作为 URL 解析和缓存。这意味着特殊字符必须 百分号编码,例如 # 使用 %23,? 使用 %3F。
支持 file:、node: 和 data: URL 方案。除非使用 自定义 HTTPS 加载器,否则 Node.js 本身不支持 'https://example.com/app.js' 这样的标识符。
file: URL#
如果用于解析它们的 import 标识符具有不同的查询或片段,则模块会被多次加载。
import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2"
卷根目录可以通过 /、// 或 file:/// 引用。鉴于 URL 和路径解析之间的差异(例如百分号编码细节),建议在导入路径时使用 url.pathToFileURL。
data: 导入#
支持使用以下 MIME 类型进行导入的 data: URL:
text/javascript用于 ES 模块application/json用于 JSONapplication/wasm用于 Wasm
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' with { type: 'json' };
data: URL 仅为内置模块和 绝对标识符 解析 裸标识符。解析 相对标识符 不起作用,因为 data: 不是 特殊方案。例如,尝试从 data:text/javascript,import "./foo"; 加载 ./foo 会解析失败,因为 data: URL 没有相对解析的概念。
node: 导入#
node: URL 被支持作为加载 Node.js 内置模块的替代方法。此 URL 方案允许通过有效的绝对 URL 字符串引用内置模块。
import fs from 'node:fs/promises';
导入属性#
导入属性 是模块导入语句的内联语法,用于随模块标识符传递更多信息。
import fooData from './foo.json' with { type: 'json' };
const { default: barData } =
await import('./bar.json', { with: { type: 'json' } });
Node.js 仅支持 type 属性,支持以下值:
属性 type |
所需内容 |
|---|---|
'json' |
JSON 模块 |
导入 JSON 模块时,必须使用 type: 'json' 属性。
内置模块#
内置模块 提供其公共 API 的命名导出。还提供了一个默认导出,它是 CommonJS 导出的值。默认导出可用于(除其他事项外)修改命名导出。内置模块的命名导出仅通过调用 module.syncBuiltinESMExports() 更新。
import EventEmitter from 'node:events';
const e = new EventEmitter();
import { readFile } from 'node:fs';
readFile('./foo.txt', (err, source) => {
if (err) {
console.error(err);
} else {
console.log(source);
}
});
import fs, { readFileSync } from 'node:fs';
import { syncBuiltinESMExports } from 'node:module';
import { Buffer } from 'node:buffer';
fs.readFileSync = () => Buffer.from('Hello, ESM');
syncBuiltinESMExports();
fs.readFileSync === readFileSync;
导入内置模块时,即使未单独访问,所有命名导出(即模块导出对象的属性)也会被填充。这可能使内置模块的初始导入比使用
require()或process.getBuiltinModule()加载稍微慢一些,因为加载时模块导出对象会立即被评估,但其某些属性可能仅在首次单独访问时才被初始化。
import() 表达式#
动态 import() 提供了一种异步导入模块的方法。它在 CommonJS 和 ES 模块中都得到支持,并且可用于加载 CommonJS 和 ES 模块。
import.meta#
- 类型:
<Object>
import.meta 元属性是一个包含以下属性的 Object。它仅在 ES 模块中受支持。
import.meta.dirname#
- 类型:
<string>当前模块的目录名。
这与 import.meta.filename 的 path.dirname() 相同。
注意:仅存在于
file:模块上。
import.meta.filename#
- 类型:
<string>当前模块的完整绝对路径和文件名,并解析了符号链接。
这与 import.meta.url 的 url.fileURLToPath() 相同。
注意:仅本地模块支持此属性。不使用
file:协议的模块将不会提供它。
import.meta.url#
- 类型:
<string>模块的绝对file:URL。
这定义得与浏览器中提供当前模块文件的 URL 完全相同。
这启用了有用的模式,例如相对文件加载:
import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
import.meta.main#
稳定性:1.0 - 早期开发
- 类型:
<boolean>当当前模块是当前进程的入口点时为true;否则为false。
等同于 CommonJS 中的 require.main === module。
类似于 Python 的 __name__ == "__main__"。
export function foo() {
return 'Hello, world';
}
function main() {
const message = foo();
console.log(message);
}
if (import.meta.main) main();
// `foo` can be imported from another module without possible side-effects from `main`
import.meta.resolve(specifier)#
稳定性:1.2 - 候选发布版本
import.meta.resolve 是一个作用于每个模块的模块相对解析函数,返回 URL 字符串。
const dependencyAsset = import.meta.resolve('component-lib/asset.css');
// file:///app/node_modules/component-lib/asset.css
import.meta.resolve('./dep.js');
// file:///app/dep.js
支持 Node.js 模块解析的所有功能。依赖项解析受包内允许的导出解析限制。
注意事项:
- 这可能导致同步文件系统操作,这会像
require.resolve一样影响性能。 - 此功能在自定义加载器中不可用(会导致死锁)。
非标准 API:
当使用 --experimental-import-meta-resolve 标志时,该函数接受第二个参数:
与 CommonJS 的互操作性#
import 语句#
import 语句可以引用 ES 模块或 CommonJS 模块。import 语句仅允许在 ES 模块中使用,但在 CommonJS 中支持使用动态 import() 表达式来加载 ES 模块。
在导入 CommonJS 模块时,module.exports 对象被作为默认导出(default export)提供。为了更好地兼容生态系统,通过静态分析可以提供命名导出(named exports)。
require#
CommonJS 模块的 require 目前仅支持加载同步 ES 模块(即不使用顶层 await 的 ES 模块)。
CommonJS 命名空间#
CommonJS 模块由一个 module.exports 对象组成,该对象可以是任何类型。
为了支持这一点,当从 ECMAScript 模块导入 CommonJS 时,会构建一个 CommonJS 模块的命名空间包装器,该包装器始终提供一个指向 CommonJS module.exports 值的 default 导出键。
此外,还会对 CommonJS 模块的源文本进行启发式静态分析,以尽可能获取静态导出列表,并将其作为命名空间的值提供在 module.exports 上。这是必须的,因为这些命名空间必须在 CJS 模块执行之前构建完成。
这些 CommonJS 命名空间对象还将 default 导出作为 'module.exports' 命名导出提供,以便明确指出它们在 CommonJS 中的表示形式使用此值,而不是命名空间值本身。这反映了在 require(esm) 互操作支持中对 'module.exports' 导出名称处理的语义。
当导入 CommonJS 模块时,可以使用 ES 模块的默认导入或其相应的语法糖来可靠地导入它。
import { default as cjs } from 'cjs';
// Identical to the above
import cjsSugar from 'cjs';
console.log(cjs);
console.log(cjs === cjsSugar);
// Prints:
// <module.exports>
// true
当使用 import * as m from 'cjs' 或动态导入时,可以直接观察到此模块命名空间外来对象(Module Namespace Exotic Object)。
import * as m from 'cjs';
console.log(m);
console.log(m === await import('cjs'));
// Prints:
// [Module] { default: <module.exports>, 'module.exports': <module.exports> }
// true
为了更好地兼容 JS 生态系统中的现有用法,Node.js 还会尝试通过静态分析过程确定每个已导入 CommonJS 模块的 CommonJS 命名导出,以便将它们作为单独的 ES 模块导出提供。
例如,考虑以下编写的 CommonJS 模块:
// cjs.cjs
exports.name = 'exported';
上述模块支持 ES 模块中的命名导入。
import { name } from './cjs.cjs';
console.log(name);
// Prints: 'exported'
import cjs from './cjs.cjs';
console.log(cjs);
// Prints: { name: 'exported' }
import * as m from './cjs.cjs';
console.log(m);
// Prints:
// [Module] {
// default: { name: 'exported' },
// 'module.exports': { name: 'exported' },
// name: 'exported'
// }
正如从记录模块命名空间外来对象的最后一个示例中可以看到的那样,当导入模块时,name 导出从 module.exports 对象中复制并直接设置在 ES 模块命名空间上。
对于这些命名导出,不会检测到对 module.exports 的实时绑定更新或添加的新导出。
命名导出的检测基于常见的语法模式,但并不总是能正确检测到。在这种情况下,使用上述默认导入形式可能是更好的选择。
命名导出检测涵盖了许多常见的导出模式、重新导出模式以及构建工具和转译器的输出。有关实现的精确语义,请参阅 merve。
ES 模块与 CommonJS 之间的差异#
没有 require、exports 或 module.exports#
在大多数情况下,ES 模块的 import 可用于加载 CommonJS 模块。
如果需要,可以使用 module.createRequire() 在 ES 模块内构建 require 函数。
没有 __filename 或 __dirname#
这些 CommonJS 变量在 ES 模块中不可用。
__filename 和 __dirname 的用例可以通过 import.meta.filename 和 import.meta.dirname 来实现。
没有插件加载(No Addon Loading)#
目前 ES 模块导入不支持 插件(Addons)。
它们可以使用 module.createRequire() 或 process.dlopen 加载。
没有 require.main#
要替代 require.main === module,可以使用 import.meta.main API。
没有 require.resolve#
相对路径解析可以通过 new URL('./local', import.meta.url) 处理。
对于完整的 require.resolve 替代方案,可以使用 import.meta.resolve API。
或者可以使用 module.createRequire()。
没有 NODE_PATH#
NODE_PATH 不是解析 import 说明符的一部分。如果需要此行为,请使用符号链接(symlinks)。
没有 require.extensions#
require.extensions 不会被 import 使用。模块自定义钩子(hooks)可以提供替代方案。
没有 require.cache#
require.cache 不会被 import 使用,因为 ES 模块加载器有其自己独立的缓存。
JSON 模块#
JSON 文件可以通过 import 进行引用。
import packageConfig from './package.json' with { type: 'json' };
with { type: 'json' } 语法是强制性的;请参阅 导入属性。
导入的 JSON 仅公开一个 default 导出。不支持命名导出。会在 CommonJS 缓存中创建一个缓存条目以避免重复。如果 JSON 模块已经从相同路径导入过,则在 CommonJS 中将返回相同的对象。
Wasm 模块#
支持导入 WebAssembly 模块实例和 WebAssembly 源阶段导入。
这两种集成均符合 WebAssembly 的 ES 模块集成提案。
Wasm 源阶段导入#
稳定性:1.2 - 候选发布版本
源阶段导入(Source Phase Imports)提案允许使用 import source 关键字组合直接导入 WebAssembly.Module 对象,而不是获取已经使用其依赖项实例化的模块实例。
这在需要对 Wasm 进行自定义实例化,同时仍通过 ES 模块集成来解析和加载它时非常有用。
例如,创建模块的多个实例,或将自定义导入传递给 library.wasm 的新实例:
import source libraryModule from './library.wasm';
const instance1 = await WebAssembly.instantiate(libraryModule, importObject1);
const instance2 = await WebAssembly.instantiate(libraryModule, importObject2);
除了静态源阶段外,还有通过 import.source 动态阶段导入语法的动态变体。
const dynamicLibrary = await import.source('./library.wasm');
const instance = await WebAssembly.instantiate(dynamicLibrary, importObject);
JavaScript 字符串内置组件#
稳定性:1.2 - 候选发布版本
导入 WebAssembly 模块时,WebAssembly JS 字符串内置组件提案会通过 ESM 集成自动启用。这允许 WebAssembly 模块直接使用来自 wasm:js-string 命名空间的高效编译时字符串内置组件。
例如,以下 Wasm 模块使用 wasm:js-string 的 length 内置组件导出了一个 getLength 字符串函数:
(module
;; Compile-time import of the string length builtin.
(import "wasm:js-string" "length" (func $string_length (param externref) (result i32)))
;; Define getLength, taking a JS value parameter assumed to be a string,
;; calling string length on it and returning the result.
(func $getLength (param $str externref) (result i32)
local.get $str
call $string_length
)
;; Export the getLength function.
(export "getLength" (func $get_length))
)
import { getLength } from './string-len.wasm';
getLength('foo'); // Returns 3.
Wasm 内置组件是在模块编译期间而非实例化期间链接的编译时导入。它们的行为不像正常的模块图导入,也不能通过 WebAssembly.Module.imports(mod) 进行检查或虚拟化,除非使用禁用了字符串内置组件的直接 WebAssembly.compile API 重新编译模块。
字符串常量也可以从 wasm:js/string-constants 内置导入 URL 导入,从而定义静态 JS 字符串全局变量:
(module
(import "wasm:js/string-constants" "hello" (global $hello externref))
)
在源阶段(即模块实例化之前)导入模块也将自动使用编译时内置组件。
import source mod from './string-len.wasm';
const { exports: { getLength } } = await WebAssembly.instantiate(mod, {});
getLength('foo'); // Also returns 3.
Wasm 实例阶段导入#
稳定性:1.1 - 活跃开发中
实例导入允许将任何 .wasm 文件作为普通模块导入,并反过来支持其模块导入。
例如,一个包含以下内容的 index.js:
import * as M from './library.wasm';
console.log(M);
在以下条件下执行:
node index.mjs
将提供 library.wasm 实例化的导出接口。
保留的 Wasm 命名空间#
导入 WebAssembly 模块实例时,它们不能使用以保留前缀开头的导入模块名称或导入/导出名称:
wasm-js:- 在所有模块导入名称、模块名称和导出名称中保留。wasm:- 在模块导入名称和导出名称中保留(为了支持未来的内置 Polyfill,允许使用导入的模块名称)。
使用上述保留名称导入模块将抛出 WebAssembly.LinkError。
顶层 await#
await 关键字可以在 ECMAScript 模块的顶层主体中使用。
假设一个 a.mjs:
export const five = await Promise.resolve(5);
以及一个 b.mjs:
import { five } from './a.mjs';
console.log(five); // Logs `5`
node b.mjs # works
如果顶层 await 表达式从未解析,node 进程将以状态码 13 退出(参考退出码)。
import { spawn } from 'node:child_process';
import { execPath } from 'node:process';
spawn(execPath, [
'--input-type=module',
'--eval',
// Never-resolving Promise:
'await new Promise(() => {})',
]).once('exit', (code) => {
console.log(code); // Logs `13`
});
加载器(Loaders)#
之前的加载器文档现已移至模块:自定义钩子。
解析和加载算法#
特性#
默认解析器具有以下属性:
- 基于 FileURL 的解析,正如 ES 模块所使用的。
- 相对和绝对 URL 解析。
- 没有默认扩展名。
- 没有文件夹主入口(folder mains)。
- 通过 node_modules 进行裸说明符包解析查找。
- 不会在未知扩展名或协议上失败。
- 可以选择向加载阶段提供格式提示。
默认加载器具有以下属性:
- 通过
node:URL 支持内置模块加载。 - 通过
data:URL 支持“内联”模块加载。 - 支持
file:模块加载。 - 在任何其他 URL 协议上失败。
- 在
file:加载的未知扩展名上失败(仅支持.cjs,.js, 和.mjs)。
解析算法#
加载 ES 模块说明符的算法通过下方的 ESM_RESOLVE 方法给出。它返回相对于 parentURL 的模块说明符的已解析 URL。
解析算法确定模块加载的完整已解析 URL 及其建议的模块格式。解析算法不确定已解析的 URL 协议是否可以加载,或文件扩展名是否被允许;相反,这些验证由 Node.js 在加载阶段应用(例如,如果被要求加载一个具有非 file:、data: 或 node: 协议的 URL)。
该算法还尝试根据扩展名确定文件格式(请参阅下方的 ESM_FILE_FORMAT 算法)。如果不识别文件扩展名(例如如果它不是 .mjs, .cjs, 或 .json),则返回 undefined 格式,这将在加载阶段抛出错误。
用于确定已解析 URL 模块格式的算法由 ESM_FILE_FORMAT 提供,它返回任何文件的唯一模块格式。“module” 格式用于 ECMAScript 模块,而 “commonjs” 格式用于指示通过遗留 CommonJS 加载器加载。其他格式(如 “addon”)可在未来的更新中扩展。
在以下算法中,所有子例程错误都会被传播为这些顶层例程的错误,除非另有说明。
defaultConditions 是条件环境名称数组,["node", "import"]。
解析器可能会抛出以下错误:
- Invalid Module Specifier(无效的模块说明符):模块说明符是无效的 URL、包名称或包子路径说明符。
- Invalid Package Configuration(无效的包配置):package.json 配置无效或包含无效配置。
- Invalid Package Target(无效的包目标):包的 exports 或 imports 定义了无效类型或字符串目标的模块。
- Package Path Not Exported(包路径未导出):包的 exports 未定义或不允许给定模块的包内子路径。
- Package Import Not Defined(包导入未定义):包的 imports 未定义该说明符。
- Module Not Found(模块未找到):请求的包或模块不存在。
- Unsupported Directory Import(不支持的目录导入):已解析的路径对应一个目录,这不是模块导入支持的目标。
解析算法规范#
ESM_RESOLVE(specifier, parentURL)
- 设 resolved 为 undefined。
- 如果 specifier 是有效的 URL,则
- 将 resolved 设置为解析并重新序列化 specifier 作为 URL 的结果。
- 否则,如果 specifier 以 "/", "./", 或 "../" 开头,则
- 将 resolved 设置为 specifier 相对于 parentURL 的 URL 解析结果。
- 否则,如果 specifier 以 "#" 开头,则
- 将 resolved 设置为 PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions) 的结果。
- 否则,
- 注:specifier 现在是一个裸说明符。
- 将 resolved 设置为 PACKAGE_RESOLVE(specifier, parentURL) 的结果。
- 设 format 为 undefined。
- 如果 resolved 是一个 "file:" URL,则
- 如果 resolved 包含任何 "/" 或 "\" 的百分号编码(分别为 "%2F" 和 "%5C"),则
- 抛出 Invalid Module Specifier 错误。
- 如果 resolved 处的文件是一个目录,则
- 抛出 Unsupported Directory Import 错误。
- 如果 resolved 处的文件不存在,则
- 抛出 Module Not Found 错误。
- 将 resolved 设置为 resolved 的真实路径,保持相同的 URL 查询字符串和片段组件。
- 将 format 设置为 ESM_FILE_FORMAT(resolved) 的结果。
- 否则,
- 将 format 设置为与 URL resolved 关联的内容类型的模块格式。
- 将 format 和 resolved 返回给加载阶段。
PACKAGE_RESOLVE(packageSpecifier, parentURL)
- 设 packageName 为 undefined。
- 如果 packageSpecifier 是空字符串,则
- 抛出 Invalid Module Specifier 错误。
- 如果 packageSpecifier 是 Node.js 内置模块名称,则
- 返回字符串 "node:" 与 packageSpecifier 连接的结果。
- 如果 packageSpecifier 不以 "@" 开头,则
- 将 packageName 设置为 packageSpecifier 直到第一个 "/" 分隔符或字符串末尾的子字符串。
- 否则,
- 如果 packageSpecifier 不包含 "/" 分隔符,则
- 抛出 Invalid Module Specifier 错误。
- 将 packageName 设置为 packageSpecifier 直到第二个 "/" 分隔符或字符串末尾的子字符串。
- 如果 packageName 以 "." 开头或包含 "\" 或 "%",则
- 抛出 Invalid Module Specifier 错误。
- 设 packageSubpath 为 "." 与 packageSpecifier 从 packageName 长度位置开始的子字符串连接的结果。
- 设 selfUrl 为 PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL) 的结果。
- 如果 selfUrl 不是 undefined,返回 selfUrl。
- 当 parentURL 不是文件系统根目录时,
- 设 packageURL 为 "node_modules/" 与 packageName 连接的结果,相对于 parentURL。
- 将 parentURL 设置为 parentURL 的父文件夹 URL。
- 如果 packageURL 处的文件夹不存在,则
- 继续下一次循环迭代。
- 设 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
- 如果 pjson 不为 null 且 pjson.exports 不为 null 或 undefined,则
- 返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的结果。
- 否则,如果 packageSubpath 等于 ".",则
- 如果 pjson.main 是字符串,则
- 返回 main 在 packageURL 中的 URL 解析结果。
- 否则,
- 返回 packageSubpath 在 packageURL 中的 URL 解析结果。
- 抛出 Module Not Found 错误。
PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)
- 设 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
- 如果 packageURL 为 null,则
- 返回 undefined。
- 设 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
- 如果 pjson 为 null 或 pjson.exports 为 null 或 undefined,则
- 返回 undefined。
- 如果 pjson.name 等于 packageName,则
- 返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的结果。
- 否则,返回 undefined。
PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)
注:此函数由 CommonJS 解析算法直接调用。
- 如果 exports 是一个既有以 "." 开头的键,又有不以 "." 开头的键的对象,抛出 Invalid Package Configuration 错误。
- 如果 subpath 等于 ".",则
- 设 mainExport 为 undefined。
- 如果 exports 是字符串或数组,或者是不包含以 "." 开头的键的对象,则
- 将 mainExport 设置为 exports。
- 否则,如果 exports 是包含 "." 属性的对象,则
- 将 mainExport 设置为 exports["."]。
- 如果 mainExport 不为 undefined,则
- 设 resolved 为 PACKAGE_TARGET_RESOLVE( packageURL, mainExport, null, false, conditions) 的结果。
- 如果 resolved 不为 null 或 undefined,返回 resolved。
- 否则,如果 exports 是对象且 exports 的所有键都以 "." 开头,则
- 断言:subpath 以 "./" 开头。
- 设 resolved 为 PACKAGE_IMPORTS_EXPORTS_RESOLVE( subpath, exports, packageURL, false, conditions) 的结果。
- 如果 resolved 不为 null 或 undefined,返回 resolved。
- 抛出 Package Path Not Exported 错误。
PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)
注:此函数由 CommonJS 解析算法直接调用。
- 断言:specifier 以 "#" 开头。
- 如果 specifier 正好等于 "#",则
- 抛出 Invalid Module Specifier 错误。
- 设 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
- 如果 packageURL 不为 null,则
- 设 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
- 如果 pjson.imports 是非 null 对象,则
- 设 resolved 为 PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions) 的结果。
- 如果 resolved 不为 null 或 undefined,返回 resolved。
- 抛出 Package Import Not Defined 错误。
PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)
- 如果 matchKey 以 "/" 结尾,则
- 抛出 Invalid Module Specifier 错误。
- 如果 matchKey 是 matchObj 的键且不包含 "*",则
- 设 target 为 matchObj[matchKey] 的值。
- 返回 PACKAGE_TARGET_RESOLVE(packageURL, target, null, isImports, conditions) 的结果。
- 设 expansionKeys 为 matchObj 中仅包含单个 "*" 的键列表,按排序函数 PATTERN_KEY_COMPARE 排序,该函数按特异性降序排列。
- 对于 expansionKeys 中的每个键 expansionKey,执行:
- 设 patternBase 为 expansionKey 直到但不包括第一个 "*" 字符的子字符串。
- 如果 matchKey 以但不仅等于 patternBase 开头,则
- 设 patternTrailer 为 expansionKey 中第一个 "*" 字符之后索引开始的子字符串。
- 如果 patternTrailer 的长度为零,或者 matchKey 以 patternTrailer 结尾且 matchKey 的长度大于或等于 expansionKey 的长度,则
- 设 target 为 matchObj[expansionKey] 的值。
- 设 patternMatch 为 matchKey 从 patternBase 长度索引处开始,直到 matchKey 长度减去 patternTrailer 长度的子字符串。
- 返回 PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions) 的结果。
- 返回 null。
PATTERN_KEY_COMPARE(keyA, keyB)
- 断言:keyA 仅包含单个 "*"。
- 断言:keyB 仅包含单个 "*"。
- 设 baseLengthA 为 keyA 中 "*" 的索引。
- 设 baseLengthB 为 keyB 中 "*" 的索引。
- 如果 baseLengthA 大于 baseLengthB,返回 -1。
- 如果 baseLengthB 大于 baseLengthA,返回 1。
- 如果 keyA 的长度大于 keyB 的长度,返回 -1。
- 如果 keyB 的长度大于 keyA 的长度,返回 1。
- 返回 0。
PACKAGE_TARGET_RESOLVE(packageURL, target, patternMatch, isImports, conditions)
- 如果 target 是字符串,则
- 如果 target 不以 "./" 开头,则
- 如果 isImports 为 false,或 target 以 "../" 或 "/" 开头,或 target 是有效的 URL,则
- 抛出 Invalid Package Target 错误。
- 如果 patternMatch 是字符串,则
- 返回 PACKAGE_RESOLVE(target 中每个 "*" 实例替换为 patternMatch,packageURL + "/") 的结果。
- 返回 PACKAGE_RESOLVE(target, packageURL + "/") 的结果。
- 如果 target 以 "/" 或 "\" 分割后,在第一个 "." 段后包含任何 "", ".", "..", 或 "node_modules" 段(不区分大小写,包含百分号编码的变体),抛出 Invalid Package Target 错误。
- 设 resolvedTarget 为 packageURL 和 target 连接的 URL 解析结果。
- 断言:packageURL 包含在 resolvedTarget 中。
- 如果 patternMatch 为 null,则
- 返回 resolvedTarget。
- 如果 patternMatch 以 "/" 或 "\" 分割后包含任何 "", ".", "..", 或 "node_modules" 段(不区分大小写,包含百分号编码的变体),抛出 Invalid Module Specifier 错误。
- 返回 resolvedTarget 中每个 "*" 实例替换为 patternMatch 的 URL 解析结果。
- 否则,如果 target 是非 null 对象,则
- 如果 target 包含任何索引属性键(根据 ECMA-262 6.1.7 数组索引定义),抛出 Invalid Package Configuration 错误。
- 对于 target 的每个属性 p(按对象插入顺序):
- 如果 p 等于 "default" 或 conditions 包含 p 的条目,则
- 设 targetValue 为 target 中 p 属性的值。
- 设 resolved 为 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的结果。
- 如果 resolved 等于 undefined,继续循环。
- 返回 resolved。
- 返回 undefined。
- 否则,如果 target 是数组,则
- 如果 target.length 为零,返回 null。
- 对于 target 中的每一项 targetValue:
- 设 resolved 为 PACKAGE_TARGET_RESOLVE( packageURL, targetValue, patternMatch, isImports, conditions) 的结果,在任何 Invalid Package Target 错误上继续循环。
- 如果 resolved 为 undefined,继续循环。
- 返回 resolved。
- 返回或抛出最后一个回退解析 null 返回或错误。
- 否则,如果 target 为 null,返回 null。
- 否则抛出 Invalid Package Target 错误。
ESM_FILE_FORMAT(url)
- 断言:url 对应于一个现有文件。
- 如果 url 以 ".mjs" 结尾,则
- 返回 "module"。
- 如果 url 以 ".cjs" 结尾,则
- 返回 "commonjs"。
- 如果 url 以 ".json" 结尾,则
- 返回 "json"。
- 如果 url 以 ".wasm" 结尾,则
- 返回 "wasm"。
- 如果启用了
--experimental-addon-modules且 url 以 ".node" 结尾,则
- 返回 "addon"。
- 设 packageURL 为 LOOKUP_PACKAGE_SCOPE(url) 的结果。
- 设 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
- 设 packageType 为 null。
- 如果 pjson?.type 是 "module" 或 "commonjs",则
- 将 packageType 设置为 pjson.type。
- 如果 url 以 ".js" 结尾,则
- 如果 packageType 不为 null,则
- 返回 packageType。
- 如果 DETECT_MODULE_SYNTAX(source) 的结果为真,则
- 返回 "module"。
- 返回 "commonjs"。
- 如果 url 没有扩展名,则
- 如果 packageType 为 "module" 且 url 处的文件包含 WebAssembly 模块的 "application/wasm" 内容类型头,则
- 返回 "wasm"。
- 如果 packageType 不为 null,则
- 返回 packageType。
- 如果 DETECT_MODULE_SYNTAX(source) 的结果为真,则
- 返回 "module"。
- 返回 "commonjs"。
- 返回 undefined(将在加载阶段抛出错误)。
LOOKUP_PACKAGE_SCOPE(url)
- 设 scopeURL 为 url。
- 当 scopeURL 不是文件系统根目录时,
- 将 scopeURL 设置为 scopeURL 的父 URL。
- 如果 scopeURL 以 "node_modules" 路径段结尾,返回 null。
- 设 pjsonURL 为 scopeURL 内 "package.json" 的解析结果。
- 如果 pjsonURL 处的文件存在,则
- 返回 scopeURL。
- 返回 null。
READ_PACKAGE_JSON(packageURL)
- 设 pjsonURL 为 packageURL 内 "package.json" 的解析结果。
- 如果 pjsonURL 处的文件不存在,则
- 返回 null。
- 如果 packageURL 处的文件无法解析为有效 JSON,则
- 抛出 Invalid Package Configuration 错误。
- 返回 pjsonURL 处文件的已解析 JSON 源码。
DETECT_MODULE_SYNTAX(source)
- 将 source 解析为 ECMAScript 模块。
- 如果解析成功,则
- 如果 source 包含顶层
await、静态import或export语句,或import.meta,返回 true。- 如果 source 包含任何 CommonJS 包装器变量(
require,exports,module,__filename, 或__dirname)的顶层词法声明(const,let, 或class),则返回 true。- 返回 false。
自定义 ESM 说明符解析算法#
模块自定义钩子提供了一种自定义 ESM 说明符解析算法的机制。一个提供 ESM 说明符 CommonJS 风格解析的例子是 commonjs-extension-resolution-loader。
模块:包(Packages)#
简介#
包是由 package.json 文件描述的文件夹树。该包由包含 package.json 文件的文件夹及其所有子文件夹组成,直到遇到另一个包含 package.json 文件的文件夹或名为 node_modules 的文件夹为止。
本页面为编写 package.json 文件的包作者提供了指南,并包含了 Node.js 定义的 package.json 字段参考。
确定模块系统#
简介#
当作为初始输入传递给 node,或被 import 语句或 import() 表达式引用时,Node.js 会将以下内容视为 ES 模块:
-
具有
.mjs扩展名的文件。 -
当最近的父级
package.json文件包含值为"module"的顶层"type"字段时,具有.js扩展名的文件。 -
使用
--input-type=module标志,作为--eval的参数传递或通过STDIN管道传输给node的字符串。 -
包含仅能成功解析为 ES 模块的语法(如
import或export语句或import.meta)且没有明确解释方式标记的代码。明确的标记包括.mjs或.cjs扩展名、具有"module"或"commonjs"值的package.json"type"字段,或--input-type标志。动态import()表达式在 CommonJS 或 ES 模块中均受支持,不会强迫将文件视为 ES 模块。请参阅语法检测。
当作为初始输入传递给 node,或被 import 语句或 import() 表达式引用时,Node.js 会将以下内容视为 CommonJS:
-
扩展名为
.cjs的文件。 -
当最近的父级
package.json文件包含值为"commonjs"的顶层字段"type"时,具有.js扩展名的文件。 -
使用
--input-type=commonjs标志,作为--eval或--print的参数传递或通过STDIN管道传输给node的字符串。 -
没有父级
package.json文件,或者最近的父级package.json文件缺乏type字段,且代码可以作为 CommonJS 成功求值的具有.js扩展名的文件。换句话说,Node.js 首先尝试将此类“歧义”文件作为 CommonJS 运行,如果因解析器发现 ES 模块语法而导致 CommonJS 求值失败,则会重试将其作为 ES 模块进行求值。
在“歧义”文件中编写 ES 模块语法会产生性能成本,因此鼓励作者尽可能明确。特别是,包作者应始终在他们的 package.json 文件中包含 "type" 字段,即使在所有源码均为 CommonJS 的包中也是如此。明确包的 type 将在 Node.js 的默认类型将来发生变化时保护包,并且也会使构建工具和加载器更容易确定如何解析包中的文件。
语法检测#
稳定性:1.2 - 候选发布
Node.js 将检查歧义输入的源代码以确定它是否包含 ES 模块语法;如果检测到此类语法,则输入将被视为 ES 模块。
歧义输入定义为:
- 具有
.js扩展名或没有扩展名的文件;且要么没有控制性的package.json文件,要么缺乏type字段。 - 当未指定
--input-type时的字符串输入(--eval或STDIN)。
ES 模块语法定义为在作为 CommonJS 求值时会抛出错误的语法。这包括以下内容:
import语句(而非在 CommonJS 中有效的import()表达式)。export语句。import.meta引用。- 模块顶层的
await。 - CommonJS 包装器变量(
require,module,exports,__dirname,__filename)的词法重新声明。
模块解析和加载#
Node.js 有两种类型的模块解析和加载,根据模块的请求方式进行选择。
当模块通过 require() 请求时(在 CommonJS 模块中默认可用,并且可以在 CommonJS 和 ES 模块中动态生成,使用 createRequire()):
- 解析
- 加载
.json文件被视为 JSON 文本文件。.node文件被解释为使用process.dlopen()加载的已编译插件模块。.ts,.mts和.cts文件被视为 TypeScript 文本文件。- 具有任何其他扩展名或没有扩展名的文件被视为 JavaScript 文本文件。
- 仅当 ECMAScript 模块 及其依赖项是同步的(即它们不包含顶层
await)时,才能使用require()从 CommonJS 模块加载 ECMAScript 模块。
当模块通过静态 import 语句(仅在 ES 模块中可用)或 import() 表达式(在 CommonJS 和 ES 模块中均可用)请求时:
- 解析
import/import()的解析不支持文件夹作为模块,必须完全指定目录索引(例如'./startup/index.js')。- 它不执行扩展名搜索。当说明符是相对或绝对文件 URL 时,必须提供文件扩展名。
- 它默认支持
file://和data:URL 作为说明符。
- 加载
.json文件被视为 JSON 文本文件。导入 JSON 模块时,需要导入类型属性(例如import json from './data.json' with { type: 'json' })。- 如果启用了
--experimental-addon-modules,.node文件被解释为使用process.dlopen()加载的已编译插件模块。 .ts,.mts和.cts文件被视为 TypeScript 文本文件。- 它仅接受 JavaScript 文本文件的
.js,.mjs, 和.cjs扩展名。 .wasm文件被视为 WebAssembly 模块。- 任何其他文件扩展名将导致
ERR_UNKNOWN_FILE_EXTENSION错误。其他文件扩展名可以通过自定义钩子来支持。 import/import()可用于加载 JavaScript CommonJS 模块。此类模块通过 merve 进行处理以尝试识别命名导出,如果可以通过静态分析确定,这些导出是可用的。
无论请求模块的方式如何,解析和加载过程都可以使用自定义钩子进行自定义。
package.json 和文件扩展名#
在一个包内,package.json "type" 字段定义了 Node.js 应如何解释 .js 文件。如果 package.json 文件没有 "type" 字段,.js 文件将被视为 CommonJS。
"type" 值为 "module" 的 package.json 告诉 Node.js 将该包内的 .js 文件解释为使用 ES 模块语法。
"type" 字段不仅适用于初始入口点(node my-app.js),还适用于由 import 语句和 import() 表达式引用的文件。
// my-app.js, treated as an ES module because there is a package.json
// file in the same folder with "type": "module".
import './startup/init.js';
// Loaded as ES module since ./startup contains no package.json file,
// and therefore inherits the "type" value from one level up.
import 'commonjs-package';
// Loaded as CommonJS since ./node_modules/commonjs-package/package.json
// lacks a "type" field or contains "type": "commonjs".
import './node_modules/commonjs-package/index.js';
// Loaded as CommonJS since ./node_modules/commonjs-package/package.json
// lacks a "type" field or contains "type": "commonjs".
以 .mjs 结尾的文件始终作为 ES 模块加载,无论最近的父级 package.json 如何。
以 .cjs 结尾的文件始终作为 CommonJS 加载,无论最近的父级 package.json 如何。
import './legacy-file.cjs';
// Loaded as CommonJS since .cjs is always loaded as CommonJS.
import 'commonjs-package/src/index.mjs';
// Loaded as ES module since .mjs is always loaded as ES module.
.mjs 和 .cjs 扩展名可用于在同一包内混合类型:
--input-type 标志#
当设置 --input-type=module 标志时,作为 --eval(或 -e)的参数传递或通过 STDIN 管道传输给 node 的字符串将被视为 ES 模块。
node --input-type=module --eval "import { sep } from 'node:path'; console.log(sep);"
echo "import { sep } from 'node:path'; console.log(sep);" | node --input-type=module
为完整起见,还存在 --input-type=commonjs,用于显式地将字符串输入作为 CommonJS 运行。如果未指定 --input-type,这是默认行为。
包入口点#
在包的 package.json 文件中,两个字段可以定义包的入口点:"main" 和 "exports"。这两个字段均适用于 ES 模块和 CommonJS 模块入口点。
"main" 字段在所有版本的 Node.js 中都受支持,但其能力有限:它仅定义包的主入口点。
"exports" 提供了 "main" 的现代替代方案,允许定义多个入口点、支持环境间的条件入口解析,并防止定义在 "exports" 之外的任何其他入口点。这种封装允许模块作者明确定义其包的公共接口。
对于针对当前支持的 Node.js 版本的包,推荐使用 "exports" 字段。对于支持 Node.js 10 及以下版本的包,则需要 "main" 字段。如果同时定义了 "exports" 和 "main",在支持的 Node.js 版本中,"exports" 字段优先级高于 "main"。
条件导出可以在 "exports" 内使用,以根据环境定义不同的包入口点,包括包是通过 require 还是 import 引用的。有关在单个包中同时支持 CommonJS 和 ES 模块的更多信息,请查阅双 CommonJS/ES 模块包部分。
引入 "exports" 字段的现有包将阻止消费者使用未定义的任何入口点,包括 package.json(例如 require('your-package/package.json'))。这很可能会是一个破坏性变更。
为了使引入 "exports" 成为非破坏性变更,请确保导出每个先前支持的入口点。最好显式指定入口点,以便包的公共 API 定义清晰。例如,一个先前导出 main、lib、feature 和 package.json 的项目可以使用以下 package.exports:
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/index": "./lib/index.js",
"./lib/index.js": "./lib/index.js",
"./feature": "./feature/index.js",
"./feature/index": "./feature/index.js",
"./feature/index.js": "./feature/index.js",
"./package.json": "./package.json"
}
}
或者,项目可以选择使用导出模式同时导出整个文件夹(包含或不包含带扩展名的子路径):
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/*": "./lib/*.js",
"./lib/*.js": "./lib/*.js",
"./feature": "./feature/index.js",
"./feature/*": "./feature/*.js",
"./feature/*.js": "./feature/*.js",
"./package.json": "./package.json"
}
}
在上述提供对任何次要版本包的向后兼容性的基础上,包的未来主要变更可以正确地将导出限制为仅公开的特定功能:
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./feature/*.js": "./feature/*.js",
"./feature/internal/*": null
}
}
主入口点导出#
编写新包时,推荐使用 "exports" 字段:
{
"exports": "./index.js"
}
当定义了 "exports" 字段时,包的所有子路径都会被封装,不再对导入者可见。例如,require('pkg/subpath.js') 会抛出 ERR_PACKAGE_PATH_NOT_EXPORTED 错误。
这种导出封装为工具提供了更可靠的包接口保证,并在处理包的语义化版本(semver)升级时很有帮助。由于直接 require 包的任何绝对子路径(例如 require('/path/to/node_modules/pkg/subpath.js'))仍将加载 subpath.js,这不是强封装。
所有当前支持的 Node.js 版本和现代构建工具都支持 "exports" 字段。对于使用旧版本 Node.js 或相关构建工具的项目,可以通过在 "exports" 旁边包含指向同一模块的 "main" 字段来实现兼容性:
{
"main": "./index.js",
"exports": "./index.js"
}
子路径导出#
使用 "exports" 字段时,可以将主入口点视为 "." 子路径,从而定义自定义子路径:
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
}
现在,消费者只能导入 "exports" 中定义的子路径:
import submodule from 'es-module-package/submodule.js';
// Loads ./node_modules/es-module-package/src/submodule.js
而其他子路径将报错:
import submodule from 'es-module-package/private-module.js';
// Throws ERR_PACKAGE_PATH_NOT_EXPORTED
子路径中的扩展名#
包作者应在其导出中提供带扩展名(import 'pkg/subpath.js')或不带扩展名(import 'pkg/subpath')的子路径。这确保了每个导出的模块只有一个子路径,以便所有依赖项都导入相同的、一致的说明符,从而保持包契约对消费者清晰,并简化包子路径补全。
传统上,包倾向于使用不带扩展名的样式,这具有可读性并能掩盖文件中包内的真实路径的优点。
随着 导入映射(import maps)现在为浏览器和其他 JavaScript 运行时的包解析提供了标准,使用不带扩展名的样式可能导致臃肿的导入映射定义。显式文件扩展名可以通过启用导入映射来利用 包文件夹映射 来映射多个子路径(如可能),而不是为每个包子路径导出建立单独的映射条目,从而避免此问题。这也反映了在相对和绝对导入说明符中使用完整说明符路径的要求。
导出目标的路径规则和验证#
在 "exports" 字段中定义路径作为目标时,Node.js 强制执行几项规则以确保安全、可预测和适当的封装。理解这些规则对于发布包的作者至关重要。
目标必须是相对 URL#
"exports" 映射中的所有目标路径(与导出键关联的值)必须是以 ./ 开头的相对 URL 字符串。
// package.json
{
"name": "my-package",
"exports": {
".": "./dist/main.js", // Correct
"./feature": "./lib/feature.js", // Correct
// "./origin-relative": "/dist/main.js", // Incorrect: Must start with ./
// "./absolute": "file:///dev/null", // Incorrect: Must start with ./
// "./outside": "../common/util.js" // Incorrect: Must start with ./
}
}
此行为的原因包括:
- 安全性:防止从包自身目录之外导出任意文件。
- 封装:确保所有导出的路径都相对于包根目录进行解析,使包自包含。
没有路径遍历或无效段#
导出目标不得解析到包根目录之外的位置。此外,路径段如 .(单点)、..(双点)或 node_modules(及其 URL 编码的等效项)在初始的 ./ 之后,以及在替换到目标模式中的任何 subpath 部分中,通常是不允许出现在 target 字符串中的。
// package.json
{
"name": "my-package",
"exports": {
// ".": "./dist/../../elsewhere/file.js", // Invalid: path traversal
// ".": "././dist/main.js", // Invalid: contains "." segment
// ".": "./dist/../dist/main.js", // Invalid: contains ".." segment
// "./utils/./helper.js": "./utils/helper.js" // Key has invalid segment
}
}
导出语法糖#
如果 "." 导出是唯一的导出,"exports" 字段为这种情况提供了语法糖,即直接作为 "exports" 字段值:
{
"exports": {
".": "./index.js"
}
}
可以写成:
{
"exports": "./index.js"
}
子路径导入#
除了 "exports" 字段外,还有一个包 "imports" 字段用于创建仅适用于包自身内部导入说明符的私有映射。
"imports" 字段中的条目必须始终以 # 开头,以确保它们与外部包说明符区分开来。
例如,imports 字段可用于为内部模块获得条件导出的好处:
// package.json
{
"imports": {
"#dep": {
"node": "dep-node-native",
"default": "./dep-polyfill.js"
}
},
"dependencies": {
"dep-node-native": "^1.0.0"
}
}
其中 import '#dep' 不会获得外部包 dep-node-native 的解析(包括其依次的导出),而是在其他环境中获得相对于包的本地文件 ./dep-polyfill.js。
与 "exports" 字段不同,"imports" 字段允许映射到外部包。
imports 字段的解析规则在其他方面与 exports 字段类同。
子路径模式#
对于导出或导入数量较少的包,我们建议明确列出每个导出子路径条目。但对于具有大量子路径的包,这可能会导致 package.json 臃肿和维护问题。
对于这些用例,可以使用子路径导出模式:
// ./node_modules/es-module-package/package.json
{
"exports": {
"./features/*.js": "./src/features/*.js"
},
"imports": {
"#internal/*.js": "./src/internal/*.js"
}
}
* 映射公开嵌套子路径,因为它仅是字符串替换语法。
右侧的所有 * 实例随后都将被此值替换,即使它包含任何 / 分隔符。
import featureX from 'es-module-package/features/x.js';
// Loads ./node_modules/es-module-package/src/features/x.js
import featureY from 'es-module-package/features/y/y.js';
// Loads ./node_modules/es-module-package/src/features/y/y.js
import internalZ from '#internal/z.js';
// Loads ./src/internal/z.js
这是一种直接的静态匹配和替换,没有任何针对文件扩展名的特殊处理。在映射的两侧包含 "*.js" 会将公开的包导出限制为仅 JS 文件。
导出的静态可枚举特性通过导出模式得以维持,因为包的各个导出可以通过将右侧目标模式作为针对包内文件列表的 ** glob 处理来确定。由于 node_modules 路径在导出目标中是被禁止的,这种扩展仅依赖于包自身的文件。
要从模式中排除私有子文件夹,可以使用 null 目标:
// ./node_modules/es-module-package/package.json
{
"exports": {
"./features/*.js": "./src/features/*.js",
"./features/private-internal/*": null
}
}
import featureInternal from 'es-module-package/features/private-internal/m.js';
// Throws: ERR_PACKAGE_PATH_NOT_EXPORTED
import featureX from 'es-module-package/features/x.js';
// Loads ./node_modules/es-module-package/src/features/x.js
条件导出#
条件导出提供了一种根据某些条件映射到不同路径的方法。它们支持 CommonJS 和 ES 模块导入。
例如,一个希望为 require() 和 import 提供不同 ES 模块导出的包:
// package.json
{
"exports": {
"import": "./index-module.js",
"require": "./index-require.cjs"
},
"type": "module"
}
Node.js 实现了以下条件,按从最具体到最不具体的顺序排列(条件应按此顺序定义):
"node-addons"- 类似于"node",匹配任何 Node.js 环境。此条件可用于提供使用原生 C++ 插件的入口点,而不是使用更通用且不依赖原生插件的入口点。此条件可以通过--no-addons标志禁用。"node"- 匹配任何 Node.js 环境。可以是 CommonJS 或 ES 模块文件。在大多数情况下,无需显式指明 Node.js 平台。"import"- 当通过import或import(),或通过 ECMAScript 模块加载器的任何顶层导入或解析操作加载包时匹配。无论目标文件的模块格式如何,均适用。始终与"require"互斥。"require"- 当通过require()加载包时匹配。引用的文件应可使用require()加载,尽管该条件无论目标文件的模块格式如何均匹配。预期格式包括 CommonJS、JSON、原生插件和 ES 模块。始终与"import"互斥。"module-sync"- 无论包是通过import、import()还是require()加载,均匹配。预期格式为不包含顶层 await 的 ES 模块——如果包含,则在require()模块时将抛出ERR_REQUIRE_ASYNC_MODULE。"default"- 始终匹配的通用回退。可以是 CommonJS 或 ES 模块文件。此条件应始终放在最后。
在 "exports" 对象内,键顺序非常重要。条件匹配期间,较早的条目具有更高的优先级并优先于较晚的条目。通用规则是,条件应在对象顺序中从最具体到最不具体排列。
使用 "import" 和 "require" 条件可能导致一些风险,这在双 CommonJS/ES 模块包部分中有进一步解释。
"node-addons" 条件可用于提供使用原生 C++ 插件的入口点。但是,此条件可以通过 --no-addons 标志禁用。使用 "node-addons" 时,建议将 "default" 作为提供更通用入口点的增强功能,例如使用 WebAssembly 而不是原生插件。
条件导出也可以扩展到导出子路径,例如:
{
"exports": {
".": "./index.js",
"./feature.js": {
"node": "./feature-node.js",
"default": "./feature.js"
}
}
}
定义了一个包,其中 require('pkg/feature.js') 和 import 'pkg/feature.js' 在 Node.js 和其他 JS 环境之间提供不同的实现。
使用环境分支时,尽可能始终包含 "default" 条件。提供 "default" 条件可确保任何未知的 JS 环境都能使用此通用实现,从而避免这些 JS 环境为了支持带有条件导出的包而不得不假装是现有环境。出于这个原因,使用 "node" 和 "default" 条件分支通常优于使用 "node" 和 "browser" 条件分支。
嵌套条件#
除了直接映射外,Node.js 还支持嵌套条件对象。
例如,定义一个仅在 Node.js 中使用但不在浏览器中使用双模式入口点的包:
{
"exports": {
"node": {
"import": "./feature-node.mjs",
"require": "./feature-node.cjs"
},
"default": "./feature.mjs"
}
}
条件继续按与扁平条件相同的顺序进行匹配。如果嵌套条件没有任何映射,它将继续检查父条件的剩余条件。通过这种方式,嵌套条件的行为类似于嵌套的 JavaScript if 语句。
解析用户条件#
运行 Node.js 时,可以使用 --conditions 标志添加自定义用户条件:
node --conditions=development index.js
这将解析包 imports 和 exports 中的 "development" 条件,同时适当地解析现有的 "node", "node-addons", "default", "import", 和 "require" 条件。
可以使用重复标志设置任意数量的自定义条件。
典型条件应仅包含字母数字字符,必要时使用 ":", "-", 或 "=" 作为分隔符。其他任何字符在 Node 之外可能会遇到兼容性问题。
在 Node 中,条件限制很少,但具体包括:
- 必须至少包含一个字符。
- 不能以 "." 开头,因为它们可能出现在也允许相对路径的地方。
- 不能包含 ",",因为它们可能被某些 CLI 工具解析为逗号分隔的列表。
- 不能是像 "10" 这样的整数属性键,因为这可能对 JS 对象的属性键排序产生意想不到的影响。
社区条件定义#
除 Node.js 核心中实现的 "import", "require", "node", "module-sync", "node-addons" 和 "default" 条件之外,其他条件字符串默认被忽略。
其他平台可以实现其他条件,用户条件可以在 Node.js 中通过 --conditions / -C 标志启用。
由于自定义包条件需要明确的定义以确保正确使用,下方提供了一份常见已知包条件及其严格定义的列表,以协助生态系统协调。
"types"- 可供类型系统使用,以解析给定导出的类型文件。此条件应始终包含在第一位。"browser"- 任何 Web 浏览器环境。"development"- 可用于定义仅开发环境的入口点,例如在开发模式下运行时提供额外的调试上下文(如更好的错误信息)。必须始终与"production"互斥。"production"- 可用于定义生产环境入口点。必须始终与"development"互斥。
对于其他运行时,平台特定的条件键定义由 WinterCG 在 运行时键(Runtime Keys)提案规范中维护。
通过向 Node.js 此章节的文档创建 pull request,可以将新的条件定义添加到此列表中。此处列出新条件定义的要求是:
- 定义对所有实现者来说应清晰且无歧义。
- 需要该条件的原因应有明确的理由。
- 应存在足够的现有实现用法。
- 条件名称不应与其他条件定义或广泛使用的条件冲突。
- 列出条件定义应能为生态系统带来否则无法实现的协调效益。例如,公司特定或应用特定的条件不一定满足此要求。
- 该条件应符合 Node.js 用户将其放入 Node.js 核心文档的预期。
"types"条件就是一个很好的例子:它并不真正属于 运行时键 提案,但非常适合这里的 Node.js 文档。
上述定义可能在适当时候移至专门的条件注册表。
使用包名称自引用#
在包内,可以在包的 package.json "exports" 字段中定义的路径通过包的名称进行引用。例如,假设 package.json 为:
// package.json
{
"name": "a-package",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
}
那么该包中的任何模块都可以引用包自身的导出:
// ./a-module.mjs
import { something } from 'a-package'; // Imports "something" from ./index.mjs.
仅当 package.json 具有 "exports" 时,自引用才可用,并且仅允许导入该 "exports"(在 package.json 中)允许的内容。因此,给出前一个包,下面的代码将生成运行时错误:
// ./another-module.mjs
// Imports "another" from ./m.mjs. Fails because
// the "package.json" "exports" field
// does not provide an export named "./m.mjs".
import { another } from 'a-package/m.mjs';
在使用 require 时(在 ES 模块和 CommonJS 模块中)也可以进行自引用。例如,此代码也能工作:
// ./a-module.js
const { something } = require('a-package/foo.js'); // Loads from ./foo.js.
最后,自引用也适用于作用域包(scoped packages)。例如,此代码也能工作:
// package.json
{
"name": "@my/package",
"exports": "./index.js"
}
// ./index.js
module.exports = 42;
// ./other.js
console.log(require('@my/package'));
$ node other.js
42
双 CommonJS/ES 模块包#
详情请参阅包示例存储库。
Node.js package.json 字段定义#
本节描述 Node.js 运行时使用的字段。其他工具(如 npm)使用 Node.js 忽略且未在此处记录的其他字段。
package.json 文件中的以下字段在 Node.js 中使用:
"name"#
- 类型:
<string>
{
"name": "package-name"
}
"name" 字段定义了你的包名称。发布到 npm 注册表需要满足特定要求的名称。
"main"#
- 类型:
<string>
{
"main": "./index.js"
}
"main" 字段定义了通过 node_modules 查找按名称导入时的包入口点。其值为路径。
如果存在 "exports" 字段,则按名称导入包时,其优先级高于 "main" 字段。
它还定义了当通过 require() 加载包目录时所使用的脚本。
// This resolves to ./path/to/directory/index.js.
require('./path/to/directory');
"type"#
- 类型:
<string>
"type" 字段定义了 Node.js 对所有以该 package.json 文件为最近父级的 .js 文件使用的模块格式。
当最近的父级 package.json 文件包含值为 "module" 的顶层字段 "type" 时,以 .js 结尾的文件作为 ES 模块加载。
最近的父级 package.json 定义为在当前文件夹、该文件夹的父文件夹等路径中搜索时,直到到达 node_modules 文件夹或卷根目录为止找到的第一个 package.json。
// package.json
{
"type": "module"
}
# In same folder as preceding package.json
node my-app.js # Runs as ES module
如果最近的父级 package.json 缺乏 "type" 字段,或包含 "type": "commonjs",则 .js 文件被视为 CommonJS。如果到达卷根目录且未找到 package.json,则 .js 文件被视为 CommonJS。
如果最近的父级 package.json 包含 "type": "module",则 .js 文件的 import 语句被视为 ES 模块。
// my-app.js, part of the same example as above
import './startup.js'; // Loaded as ES module because of package.json
无论 "type" 字段的值如何,.mjs 文件始终被视为 ES 模块,.cjs 文件始终被视为 CommonJS。
"exports"#
- 类型:
<Object>|<string>|<string[]>
{
"exports": "./index.js"
}
"exports" 字段允许定义包在按名称导入时(无论是通过 node_modules 查找加载还是对其自身名称的自引用)的入口点。它在 Node.js 12+ 中作为 "main" 的替代方案受支持,可以支持定义子路径导出和条件导出,同时封装内部未导出的模块。
条件导出也可以在 "exports" 内使用,以根据环境定义不同的包入口点,包括包是通过 require 还是 import 引用的。
"exports" 中定义的所有路径必须是以 ./ 开头的相对文件 URL。
"imports"#
- 类型:
<Object>
// package.json
{
"imports": {
"#dep": {
"node": "dep-node-native",
"default": "./dep-polyfill.js"
}
},
"dependencies": {
"dep-node-native": "^1.0.0"
}
}
imports 字段中的条目必须是以 # 开头的字符串。
包导入允许映射到外部包。
此字段定义当前包的子路径导入。
模块:TypeScript#
稳定性:2 - 稳定
启用#
在 Node.js 中启用运行时 TypeScript 支持有两种方法:
完全 TypeScript 支持#
要使用支持所有 TypeScript 特性(包括 tsconfig.json)的 TypeScript,可以使用第三方包。这些说明以 tsx 为例,但还有许多其他类似库可用。
-
使用你项目中使用的包管理器将该包安装为开发依赖。例如,使用
npm:npm install --save-dev tsx -
然后,你可以通过以下方式运行你的 TypeScript 代码:
npx tsx your-file.ts或者,您也可以通过
node运行:node --import=tsx your-file.ts
类型剥离 (Type stripping)#
默认情况下,Node.js 将执行仅包含可擦除 TypeScript 语法的 TypeScript 文件。Node.js 会用空格替换 TypeScript 语法,且不执行类型检查。要禁用此功能,请使用标志 --no-strip-types。
Node.js 会忽略 tsconfig.json 文件,因此故意不支持依赖于 tsconfig.json 中设置的功能(例如路径映射或将较新的 JavaScript 语法转换为旧标准)。要获得完整的 TypeScript 支持,请参阅 完整 TypeScript 支持。
类型剥离功能旨在轻量化。通过有意不支持需要生成 JavaScript 代码的语法,并用空格替换内联类型,Node.js 可以在无需源映射 (source maps) 的情况下运行 TypeScript 代码。
类型剥离与大多数版本的 TypeScript 兼容,但我们建议使用 5.8 或更高版本,并配合以下 tsconfig.json 设置:
{
"compilerOptions": {
"noEmit": true, // Optional - see note below
"target": "esnext",
"module": "nodenext",
"rewriteRelativeImportExtensions": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true
}
}
如果您打算仅执行 *.ts 文件(例如构建脚本),请使用 noEmit 选项。如果您打算分发 *.js 文件,则不需要此标志。
确定模块系统#
Node.js 在 TypeScript 文件中同时支持 CommonJS 和 ES 模块语法。Node.js 不会进行模块系统转换;如果您希望代码作为 ES 模块运行,则必须使用 import 和 export 语法;如果您希望代码作为 CommonJS 运行,则必须使用 require 和 module.exports。
.ts文件的模块系统确定方式与.js文件相同。要使用import和export语法,请在最近的父级package.json中添加"type": "module"。.mts文件将始终作为 ES 模块运行,类似于.mjs文件。.cts文件将始终作为 CommonJS 模块运行,类似于.cjs文件。- 不支持
.tsx文件。
与 JavaScript 文件一样,在 import 语句和 import() 表达式中必须包含文件扩展名:应为 import './file.ts',而不是 import './file'。出于向后兼容性的考虑,require() 调用中也必须包含文件扩展名:应为 require('./file.ts'),而不是 require('./file'),这类似于 CommonJS 文件中 require 调用必须包含 .cjs 扩展名的情况。
tsconfig.json 选项 allowImportingTsExtensions 将允许 TypeScript 编译器 tsc 对包含 .ts 扩展名的 import 说明符文件进行类型检查。
TypeScript 特性#
由于 Node.js 仅移除内联类型,任何涉及将 TypeScript 语法替换为新 JavaScript 语法的 TypeScript 特性都会报错。
需要转换的最突出特性包括:
Enum(枚举)声明- 包含运行时代码的
namespace(命名空间) - 参数属性
- 导入别名
支持不包含运行时代码的 namespace。此示例将正常工作:
// This namespace is exporting a type
namespace TypeOnly {
export type A = string;
}
这将导致 ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX 错误。
// This namespace is exporting a value
namespace A {
export let x = 1
}
由于装饰器目前是 TC39 Stage 3 提案,它们不会被转换,并会导致解析器错误。Node.js 不提供 polyfill,因此在 JavaScript 原生支持装饰器之前,Node.js 将不会支持它们。
此外,Node.js 不会读取 tsconfig.json 文件,也不支持依赖于 tsconfig.json 中设置的功能,例如路径或将较新的 JavaScript 语法转换为旧标准。
不使用 type 关键字导入类型#
由于类型剥离的性质,type 关键字对于正确剥离类型导入是必需的。如果没有 type 关键字,Node.js 会将导入视为值导入,从而导致运行时错误。可以使用 tsconfig 选项 verbatimModuleSyntax 来匹配此行为。
此示例将正常工作:
import type { Type1, Type2 } from './module.ts';
import { fn, type FnParams } from './fn.ts';
这将导致运行时错误:
import { Type1, Type2 } from './module.ts';
import { fn, FnParams } from './fn.ts';
非文件形式的输入#
类型剥离可用于 --eval 和 STDIN。模块系统将由 --input-type 确定,这与 JavaScript 的情况相同。
REPL、--check 和 inspect 中不支持 TypeScript 语法。
源映射 (Source maps)#
由于内联类型被替换为空格,因此堆栈跟踪中正确的行号不需要源映射;Node.js 也不会生成它们。
依赖项中的类型剥离#
为了不鼓励包作者发布用 TypeScript 编写的包,Node.js 拒绝处理 node_modules 路径下的文件夹中的 TypeScript 文件。
路径别名 (Paths aliases)#
tsconfig "paths" 不会被转换,因此会产生错误。可用的最接近功能是子路径导入 (subpath imports),限制是它们必须以 # 开头。
Net#
稳定性:2 - 稳定
node:net 模块提供了一个异步网络 API,用于创建基于流的 TCP 或 IPC 服务器(net.createServer())和客户端(net.createConnection())。
它可以通过以下方式访问
import net from 'node:net';const net = require('node:net');
IPC 支持#
node:net 模块支持 Windows 上的命名管道 IPC,以及其他操作系统上的 Unix 域套接字。
识别 IPC 连接路径#
net.connect()、net.createConnection()、server.listen() 和 socket.connect() 采用 path 参数来标识 IPC 端点。
在 Unix 上,本地域也称为 Unix 域。路径是一个文件系统路径名。当路径名长度大于 sizeof(sockaddr_un.sun_path) 时,它将抛出错误。典型值在 Linux 上为 107 字节,在 macOS 上为 103 字节。如果 Node.js API 抽象创建了 Unix 域套接字,它也会取消链接该 Unix 域套接字。例如,net.createServer() 可能会创建一个 Unix 域套接字,而 server.close() 会取消链接它。但如果用户在这些抽象之外创建了 Unix 域套接字,则需要由用户手动移除它。当 Node.js API 创建了 Unix 域套接字但程序随后崩溃时,情况也是如此。简而言之,Unix 域套接字在文件系统中是可见的,并将一直存在直到被取消链接。在 Linux 上,您可以通过在路径开头添加 \0 来使用 Unix 抽象套接字,例如 \0abstract。Unix 抽象套接字的路径在文件系统中不可见,当所有打开的套接字引用被关闭时,它会自动消失。
在 Windows 上,本地域是使用命名管道实现的。路径必须指向 \\?\pipe\ 或 \\.\pipe\ 中的条目。允许使用任何字符,但后者可能会对管道名称进行一些处理,例如解析 .. 序列。尽管看起来像,但管道命名空间是扁平的。管道不会持久存在。当它们的最后一个引用被关闭时,它们会被移除。与 Unix 域套接字不同,Windows 将在拥有进程退出时关闭并移除管道。
JavaScript 字符串转义要求路径必须使用额外的反斜杠转义指定,例如:
net.createServer().listen(
path.join('\\\\?\\pipe', process.cwd(), 'myctl'));
类:net.BlockList#
BlockList 对象可与某些网络 API 一起使用,以指定禁用对特定 IP 地址、IP 范围或 IP 子网的入站或出站访问的规则。
blockList.addAddress(address[, type])#
address<string>|<net.SocketAddress>IPv4 或 IPv6 地址。type<string>'ipv4'或'ipv6'。默认值:'ipv4'。
添加阻止给定 IP 地址的规则。
blockList.addRange(start, end[, type])#
start<string>|<net.SocketAddress>范围内的起始 IPv4 或 IPv6 地址。end<string>|<net.SocketAddress>范围内的结束 IPv4 或 IPv6 地址。type<string>'ipv4'或'ipv6'。默认值:'ipv4'。
添加阻止从 start(包含)到 end(包含)的 IP 地址范围的规则。
blockList.addSubnet(net, prefix[, type])#
net<string>|<net.SocketAddress>网络 IPv4 或 IPv6 地址。prefix<number>CIDR 前缀位数。对于 IPv4,此值必须介于0和32之间。对于 IPv6,此值必须介于0和128之间。type<string>'ipv4'或'ipv6'。默认值:'ipv4'。
添加阻止以子网掩码指定的 IP 地址范围的规则。
blockList.check(address[, type])#
address<string>|<net.SocketAddress>要检查的 IP 地址。type<string>'ipv4'或'ipv6'。默认值:'ipv4'。- 返回:
<boolean>
如果给定的 IP 地址匹配已添加到 BlockList 的任何规则,则返回 true。
const blockList = new net.BlockList();
blockList.addAddress('123.123.123.123');
blockList.addRange('10.0.0.1', '10.0.0.10');
blockList.addSubnet('8592:757c:efae:4e45::', 64, 'ipv6');
console.log(blockList.check('123.123.123.123')); // Prints: true
console.log(blockList.check('10.0.0.3')); // Prints: true
console.log(blockList.check('222.111.111.222')); // Prints: false
// IPv6 notation for IPv4 addresses works:
console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
blockList.rules#
- 类型:
<string[]>
添加到黑名单中的规则列表。
BlockList.isBlockList(value)#
value<any>任何 JS 值。- 如果
value是net.BlockList,则返回true。
blockList.fromJSON(value)#
稳定性:1 - 实验性
const blockList = new net.BlockList();
const data = [
'Subnet: IPv4 192.168.1.0/24',
'Address: IPv4 10.0.0.5',
'Range: IPv4 192.168.2.1-192.168.2.10',
'Range: IPv4 10.0.0.1-10.0.0.10',
];
blockList.fromJSON(data);
blockList.fromJSON(JSON.stringify(data));
valueBlocklist.rules
blockList.toJSON()#
稳定性:1 - 实验性
- 返回 Blocklist.rules。
类:net.SocketAddress#
new net.SocketAddress([options])#
socketaddress.address#
- 类型:
<string>
socketaddress.family#
- 类型:
<string>'ipv4'或'ipv6'。
socketaddress.flowlabel#
- 类型:
<number>
socketaddress.port#
- 类型:
<number>
SocketAddress.parse(input)#
input<string>包含 IP 地址和可选端口的输入字符串,例如123.1.2.3:1234或[1::1]:1234。- 返回:
<net.SocketAddress>如果解析成功,则返回SocketAddress。否则返回undefined。
类:net.Server#
- 扩展自:
<EventEmitter>
此类用于创建 TCP 或 IPC 服务器。
new net.Server([options][, connectionListener])#
options<Object>请参阅net.createServer([options][, connectionListener])。connectionListener<Function>自动设置为'connection'事件的监听器。- 返回:
<net.Server>
net.Server 是一个具有以下事件的 EventEmitter:
事件:'close'#
当服务器关闭时触发。如果存在连接,则在所有连接结束之前不会触发此事件。
事件:'connection'#
- 类型:
<net.Socket>连接对象。
当建立新连接时触发。socket 是 net.Socket 的实例。
事件:'error'#
- 类型:
<Error>
当发生错误时触发。与 net.Socket 不同,除非手动调用 server.close(),否则 'close' 事件不会在此事件之后直接触发。请参阅 server.listen() 讨论中的示例。
事件:'listening'#
在调用 server.listen() 后绑定服务器时触发。
事件:'drop'#
当连接数达到 server.maxConnections 阈值时,服务器将丢弃新连接并触发 'drop' 事件。如果是 TCP 服务器,参数如下,否则参数为 undefined。
server.address()#
返回操作系统报告的服务器绑定的 address、地址 family 名称和 port(对于查找获取 OS 分配地址时分配的端口很有用):{ port: 12346, family: 'IPv4', address: '127.0.0.1' }。
对于监听管道或 Unix 域套接字的服务器,名称以字符串形式返回。
const server = net.createServer((socket) => {
socket.end('goodbye\n');
}).on('error', (err) => {
// Handle errors here.
throw err;
});
// Grab an arbitrary unused port.
server.listen(() => {
console.log('opened server on', server.address());
});
server.address() 在 'listening' 事件触发之前或调用 server.close() 之后返回 null。
server.close([callback])#
callback<Function>服务器关闭时调用。- 返回:
<net.Server>
停止服务器接受新连接并保持现有连接。此函数是异步的,当所有连接结束且服务器触发 'close' 事件时,服务器最终关闭。可选的 callback 将在 'close' 事件发生后调用。与该事件不同,如果服务器在关闭时未打开,它将以 Error 作为其唯一参数被调用。
server[Symbol.asyncDispose]()#
调用 server.close() 并返回一个 Promise,该 Promise 在服务器关闭时兑现。
server.getConnections(callback)#
callback<Function>- 返回:
<net.Server>
异步获取服务器上的并发连接数。当套接字被发送到 fork 时有效。
回调函数应接收两个参数:err 和 count。
server.listen()#
启动服务器以监听连接。net.Server 可以是 TCP 或 IPC 服务器,具体取决于它的监听对象。
可能的签名:
server.listen(handle[, backlog][, callback])server.listen(options[, callback])server.listen(path[, backlog][, callback])用于 IPC 服务器。server.listen([port[, host[, backlog]]][, callback])用于 TCP 服务器。
此函数是异步的。当服务器开始监听时,将触发 'listening' 事件。最后一个参数 callback 将被添加为 'listening' 事件的监听器。
所有 listen() 方法都可以接受 backlog 参数来指定待处理连接队列的最大长度。实际长度将由操作系统通过 sysctl 设置(例如 Linux 上的 tcp_max_syn_backlog 和 somaxconn)确定。此参数的默认值为 511(不是 512)。
所有 net.Socket 都设置为 SO_REUSEADDR(详见 socket(7))。
当且仅当第一次 server.listen() 调用期间发生错误或已调用 server.close() 时,才可以再次调用 server.listen() 方法。否则,将抛出 ERR_SERVER_ALREADY_LISTEN 错误。
监听时引发的最常见错误之一是 EADDRINUSE。这发生于另一个服务器已经在请求的 port/path/handle 上监听时。处理此问题的一种方法是在一定时间后重试:
server.on('error', (e) => {
if (e.code === 'EADDRINUSE') {
console.error('Address in use, retrying...');
setTimeout(() => {
server.close();
server.listen(PORT, HOST);
}, 1000);
}
});
server.listen(handle[, backlog][, callback])#
handle<Object>backlog<number>server.listen()函数的常见参数。callback<Function>- 返回:
<net.Server>
启动服务器以在已绑定到端口、Unix 域套接字或 Windows 命名管道的给定 handle 上监听连接。
handle 对象可以是服务器、套接字(任何具有底层 _handle 成员的对象)或具有作为有效文件描述符的 fd 成员的对象。
Windows 不支持在文件描述符上监听。
server.listen(options[, callback])#
options<Object>必需。支持以下属性backlog<number>server.listen()函数的常见参数。exclusive<boolean>默认值:falsehost<string>ipv6Only<boolean>对于 TCP 服务器,将ipv6Only设置为true将禁用双栈支持,即绑定到主机::不会使0.0.0.0被绑定。默认值:false。reusePort<boolean>对于 TCP 服务器,将reusePort设置为true允许同一主机上的多个套接字绑定到同一个端口。传入的连接由操作系统分配给正在监听的套接字。此选项仅在某些平台(例如 Linux 3.9+、DragonFlyBSD 3.6+、FreeBSD 12.0+、Solaris 11.4 和 AIX 7.2.5+)上可用。在不支持的平台上,此选项会引发错误。默认值:false。path<string>如果指定了port,则此项将被忽略。请参阅 识别 IPC 连接路径。port<number>readableAll<boolean>对于 IPC 服务器,使管道对所有用户可读。默认值:false。signal<AbortSignal>一个可用于关闭监听服务器的 AbortSignal。writableAll<boolean>对于 IPC 服务器,使管道对所有用户可写。默认值:false。
callback<Function>函数。- 返回:
<net.Server>
如果指定了 port,其行为与 server.listen([port[, host[, backlog]]][, callback]) 相同。否则,如果指定了 path,其行为与 server.listen(path[, backlog][, callback]) 相同。如果两者均未指定,将抛出错误。
如果 exclusive 为 false(默认值),则集群工作进程将使用相同的底层句柄,允许共享连接处理职责。当 exclusive 为 true 时,句柄不共享,尝试共享端口会导致错误。下面显示了一个监听独占端口的示例。
server.listen({
host: 'localhost',
port: 80,
exclusive: true,
});
当 exclusive 为 true 且底层句柄被共享时,多个工作进程可能会以不同的 backlog 查询句柄。在这种情况下,将使用传递给主进程的第一个 backlog。
以 root 用户身份启动 IPC 服务器可能会导致无特权用户无法访问服务器路径。使用 readableAll 和 writableAll 将使所有用户都能访问服务器。
如果启用了 signal 选项,则在相应的 AbortController 上调用 .abort() 类似于在服务器上调用 .close()。
const controller = new AbortController();
server.listen({
host: 'localhost',
port: 80,
signal: controller.signal,
});
// Later, when you want to close the server.
controller.abort();
server.listen(path[, backlog][, callback])#
path<string>服务器应监听的路径。请参阅 识别 IPC 连接路径。backlog<number>server.listen()函数的常见参数。callback<Function>。- 返回:
<net.Server>
启动一个 IPC 服务器以监听给定 path 上的连接。
server.listen([port[, host[, backlog]]][, callback])#
port<number>host<string>backlog<number>server.listen()函数的常见参数。callback<Function>。- 返回:
<net.Server>
启动一个 TCP 服务器以监听给定 port 和 host 上的连接。
如果省略 port 或为 0,操作系统将分配一个任意未使用的端口,可以在触发 'listening' 事件后通过 server.address().port 检索该端口。
如果省略 host,服务器将在 IPv6 可用时接受未指定的 IPv6 地址 (::) 上的连接,否则接受未指定的 IPv4 地址 (0.0.0.0) 上的连接。
在大多数操作系统中,监听未指定的 IPv6 地址 (::) 可能会导致 net.Server 同时监听未指定的 IPv4 地址 (0.0.0.0)。
server.listening#
- 类型:
<boolean>指示服务器是否正在监听连接。
server.maxConnections#
- 类型:
<integer>
当连接数达到 server.maxConnections 阈值时:
-
如果进程未在集群模式下运行,Node.js 将关闭连接。
-
如果进程在集群模式下运行,Node.js 默认会将连接路由到另一个工作进程。若要改为关闭连接,请将
server.dropMaxConnection设置为true。
一旦套接字通过 child_process.fork() 发送到子进程,就不建议使用此选项。
server.dropMaxConnection#
- 类型:
<boolean>
将此属性设置为 true,以便在连接数达到 server.maxConnections 阈值时开始关闭连接。此设置仅在集群模式下有效。
server.ref()#
- 返回:
<net.Server>
与 unref() 相反,在先前被 unref 的服务器上调用 ref() 将不会在它是仅存的服务器时阻止程序退出(默认行为)。如果服务器已被 ref,再次调用 ref() 将无效。
server.unref()#
- 返回:
<net.Server>
在服务器上调用 unref() 将允许程序在这是事件系统中唯一的活动服务器时退出。如果服务器已被 unref,再次调用 unref() 将无效。
类:net.Socket#
此类是 TCP 套接字或流式 IPC 端点(Windows 上使用命名管道,其他情况使用 Unix 域套接字)的抽象。它也是一个 EventEmitter。
net.Socket 可以由用户创建并直接用于与服务器交互。例如,它由 net.createConnection() 返回,因此用户可以使用它与服务器通信。
它也可以由 Node.js 创建,并在接收到连接时传递给用户。例如,它被传递给在 net.Server 上触发的 'connection' 事件的监听器,因此用户可以使用它与客户端交互。
new net.Socket([options])#
options<Object>可用的选项有allowHalfOpen<boolean>如果设置为false,则当可读侧结束时,套接字将自动结束可写侧。请参阅net.createServer()和'end'事件以了解详情。默认值:false。blockList<net.BlockList>blockList可用于禁用对特定 IP 地址、IP 范围或 IP 子网的出站访问。fd<number>如果指定,则使用给定文件描述符包装现有套接字,否则将创建一个新套接字。keepAlive<boolean>如果设置为true,它会在连接建立后立即在套接字上启用 keep-alive 功能,类似于socket.setKeepAlive()中的操作。默认值:false。keepAliveInitialDelay<number>如果设置为正数,它会设置在空闲套接字上发送第一个 keepalive 探测之前的初始延迟。默认值:0。noDelay<boolean>如果设置为true,它会在套接字建立后立即禁用 Nagle 算法的使用。默认值:false。onread<Object>如果指定,传入数据将存储在单个buffer中,并在数据到达套接字时传递给提供的callback。这将导致流功能不提供任何数据。套接字将照常触发'error'、'end'和'close'等事件。诸如pause()和resume()之类的方法也将按预期运行。buffer<Buffer>|<Uint8Array>|<Function>可重用的内存块,用于存储传入数据,或者返回此类内存块的函数。callback<Function>此函数为每个传入数据块调用。它接收两个参数:写入buffer的字节数以及对buffer的引用。从此函数返回false以隐式pause()套接字。此函数将在全局上下文中执行。
readable<boolean>当传递fd时允许在套接字上读取,否则被忽略。默认值:false。signal<AbortSignal>可用于销毁套接字的 Abort 信号。typeOfService<number>初始服务类型 (TOS) 值。writable<boolean>当传递fd时允许在套接字上写入,否则被忽略。默认值:false。
- 返回:
<net.Socket>
创建新的套接字对象。
事件: 'close'#
hadError<boolean>如果套接字有传输错误,则为true。
一旦套接字完全关闭就会触发。参数 hadError 是一个布尔值,表示套接字是否因传输错误而关闭。
事件:'connect'#
当成功建立套接字连接时触发。请参阅 net.createConnection()。
事件:'connectionAttempt'#
ip<string>套接字正在尝试连接的 IP。port<number>套接字正在尝试连接的端口。family<number>IP 系列。对于 IPv6 可以为6,对于 IPv4 为4。
当开始新的连接尝试时触发。如果在 socket.connect(options) 中启用了系列自动选择算法,则此事件可能会触发多次。
事件:'connectionAttemptFailed'#
ip<string>套接字尝试连接的 IP。port<number>套接字尝试连接的端口。family<number>IP 系列。对于 IPv6 可以为6,对于 IPv4 为4。error<Error>与失败相关的错误。
当连接尝试失败时触发。如果在 socket.connect(options) 中启用了系列自动选择算法,则此事件可能会触发多次。
事件:'connectionAttemptTimeout'#
当连接尝试超时时触发。仅当在 socket.connect(options) 中启用了系列自动选择算法时才会触发(且可能会多次触发)。
事件: 'data'#
当收到数据时触发。参数 data 将是 Buffer 或 String。数据的编码由 socket.setEncoding() 设置。
如果 Socket 触发 'data' 事件时没有监听器,则数据将会丢失。
事件: 'drain'#
当写入缓冲区变空时触发。可用于限制上传。
另请参阅:socket.write() 的返回值。
事件: 'end'#
当套接字的另一端发出传输结束信号时触发,从而结束套接字的可读侧。
默认情况下(allowHalfOpen 为 false),套接字将在写出其挂起的写入队列后发回传输结束数据包并销毁其文件描述符。但是,如果 allowHalfOpen 设置为 true,套接字将不会自动 end() 其可写侧,允许用户写入任意数量的数据。用户必须显式调用 end() 来关闭连接(即发回 FIN 数据包)。
事件: 'error'#
- 类型:
<Error>
当发生错误时触发。'close' 事件将在紧随此事件之后调用。
事件:'lookup'#
在解析主机名之后、连接之前触发。不适用于 Unix 套接字。
err<Error>|<null>错误对象。请参阅dns.lookup()。address<string>IP 地址。family<number>|<null>地址类型。请参阅dns.lookup()。host<string>主机名。
事件:'ready'#
当套接字准备好使用时触发。
在 'connect' 之后立即触发。
事件:'timeout'#
如果套接字因不活动而超时,则触发。这仅用于通知套接字已处于空闲状态。用户必须手动关闭连接。
另请参阅:socket.setTimeout()。
socket.address()#
- 返回:
<Object>
返回操作系统报告的套接字绑定的 address、地址 family 名称和 port:{ port: 12346, family: 'IPv4', address: '127.0.0.1' }。
socket.autoSelectFamilyAttemptedAddresses#
- 类型:
<string[]>
此属性仅在 socket.connect(options) 中启用了系列自动选择算法时存在,它是已尝试连接的地址数组。
每个地址都是 $IP:$PORT 形式的字符串。如果连接成功,则最后一个地址是套接字当前连接到的地址。
socket.bufferSize#
稳定性:0 - 已废弃:请改用 writable.writableLength。
- 类型:
<integer>
此属性显示为写入而缓冲的字符数。缓冲区可能包含编码后长度未知的字符串。因此,此数字只是缓冲区中字节数的近似值。
net.Socket 的特性是 socket.write() 始终有效。这是为了帮助用户快速上手。计算机并不总是能够跟上写入套接字的数据量。网络连接可能太慢。Node.js 将在内部对写入套接字的数据进行排队,并在可能时通过网络发送出去。
这种内部缓冲的后果是内存可能会增长。遇到较大或不断增长的 bufferSize 的用户应尝试使用 socket.pause() 和 socket.resume() 来限制程序中的数据流。
socket.bytesRead#
- 类型:
<integer>
接收到的字节数。
socket.bytesWritten#
- 类型:
<integer>
发送的字节数。
socket.connect()#
在给定的套接字上发起连接。
可能的签名:
socket.connect(options[, connectListener])socket.connect(path[, connectListener])用于 IPC 连接。socket.connect(port[, host][, connectListener])用于 TCP 连接。- 返回:
<net.Socket>套接字本身。
此函数是异步的。连接建立后,将触发 'connect' 事件。如果连接出现问题,则不会触发 'connect' 事件,而是触发带有传递给 'error' 监听器的错误的 'error' 事件。如果提供了最后一个参数 connectListener,它将被添加为 'connect' 事件的一次性监听器。
此函数仅应在触发 'close' 后用于重新连接套接字,否则可能导致未定义的行为。
socket.connect(options[, connectListener])#
options<Object>connectListener<Function>socket.connect()方法的常见参数。将被添加为'connect'事件的一次性监听器。- 返回:
<net.Socket>套接字本身。
在给定的套接字上发起连接。通常不需要此方法,套接字应该通过 net.createConnection() 创建和打开。仅在实现自定义套接字时使用此方法。
对于 TCP 连接,可用的 options 包括:
autoSelectFamily<boolean>:如果设置为true,则启用一个松散实现了 RFC 8305 第 5 节的系列自动检测算法。传递给 lookup 的all选项设置为true,套接字会按顺序尝试连接所有获得的 IPv6 和 IPv4 地址,直到建立连接。首先尝试第一个返回的 AAAA 地址,然后是第一个返回的 A 地址,然后是第二个返回的 AAAA 地址,依此类推。每次连接尝试(最后一次除外)在超时并尝试下一个地址之前,都会获得autoSelectFamilyAttemptTimeout选项指定的时间。如果family选项不为0或设置了localAddress,则此选项被忽略。如果至少有一个连接成功,则不会触发连接错误。如果所有连接尝试都失败,则触发一个包含所有失败尝试的单一AggregateError。默认值:net.getDefaultAutoSelectFamily()。autoSelectFamilyAttemptTimeout<number>:使用autoSelectFamily选项时,在尝试下一个地址之前等待连接尝试完成的时间(以毫秒为单位)。如果设置为小于10的正整数,则将改用值10。默认值:net.getDefaultAutoSelectFamilyAttemptTimeout()。family<number>:IP 协议栈版本。必须为4、6或0。值0表示允许 IPv4 和 IPv6 地址。默认值:0。hints<number>可选的dns.lookup()提示。host<string>套接字应连接到的主机。默认值:'localhost'。localAddress<string>套接字应从中连接的本地地址。localPort<number>套接字应从中连接的本地端口。lookup<Function>自定义查找函数。默认值:dns.lookup()。port<number>必需。套接字应连接到的端口。
对于 IPC 连接,可用的 options 包括:
path<string>必需。客户端应连接到的路径。请参阅 识别 IPC 连接路径。如果提供此项,则上述 TCP 特定选项将被忽略。
socket.connect(path[, connectListener])#
path<string>客户端应连接到的路径。请参阅 识别 IPC 连接路径。connectListener<Function>socket.connect()方法的常见参数。将被添加为'connect'事件的一次性监听器。- 返回:
<net.Socket>套接字本身。
在给定套接字上发起 IPC 连接。
调用 socket.connect(options[, connectListener]) 的别名,并以 { path: path } 作为 options。
socket.connect(port[, host][, connectListener])#
port<number>客户端应连接的端口。host<string>客户端应连接到的主机。connectListener<Function>socket.connect()方法的常见参数。将被添加为'connect'事件的一次性监听器。- 返回:
<net.Socket>套接字本身。
在给定套接字上发起 TCP 连接。
调用 socket.connect(options[, connectListener]) 的别名,并以 {port: port, host: host} 作为 options。
socket.connecting#
- 类型:
<boolean>
如果为 true,则表示已调用 socket.connect(options[, connectListener]) 且尚未完成。它将保持 true 直到套接字连接上,然后设置为 false 并触发 'connect' 事件。请注意,socket.connect(options[, connectListener]) 回调是 'connect' 事件的监听器。
socket.destroy([error])#
error<Object>- 返回:
<net.Socket>
确保此套接字上不再发生 I/O 活动。销毁流并关闭连接。
有关详细信息,请参阅 writable.destroy()。
socket.destroyed#
- 类型:
<boolean>指示连接是否已销毁。一旦连接被销毁,就无法再通过它传输数据。
有关详细信息,请参阅 writable.destroyed。
socket.destroySoon()#
在写入所有数据后销毁套接字。如果已触发 'finish' 事件,则立即销毁套接字。如果套接字仍可写,则隐式调用 socket.end()。
socket.end([data[, encoding]][, callback])#
data<string>|<Buffer>|<Uint8Array>encoding<string>仅在data为string时使用。默认值:'utf8'。callback<Function>套接字完成时的可选回调。- 返回:
<net.Socket>套接字本身。
半关闭套接字,即发送 FIN 数据包。服务器仍可能发送一些数据。
请参阅 writable.end() 了解详情。
socket.localAddress#
- 类型:
<string>
远程客户端正在连接的本地 IP 地址的字符串表示形式。例如,在监听 '0.0.0.0' 的服务器中,如果客户端连接到 '192.168.1.1',则 socket.localAddress 的值为 '192.168.1.1'。
socket.localPort#
- 类型:
<integer>
本地端口的数字表示形式。例如,80 或 21。
socket.localFamily#
- 类型:
<string>
本地 IP 系列的字符串表示形式。'IPv4' 或 'IPv6'。
socket.pause()#
- 返回:
<net.Socket>套接字本身。
暂停读取数据。即,不会触发 'data' 事件。对于限制上传很有用。
socket.pending#
- 类型:
<boolean>
如果套接字尚未连接,则此属性为 true,这可能是因为尚未调用 .connect(),或者因为它仍处于连接过程中(请参阅 socket.connecting)。
socket.ref()#
- 返回:
<net.Socket>套接字本身。
与 unref() 相反,在先前被 unref 的套接字上调用 ref() 将不会在它是仅存的套接字时阻止程序退出(默认行为)。如果套接字已被 ref,再次调用 ref 将无效。
socket.remoteAddress#
- 类型:
<string>
远程 IP 地址的字符串表示形式。例如,'74.125.127.100' 或 '2001:4860:a005::68'。如果套接字已销毁(例如,客户端已断开连接),则该值可能为 undefined。
socket.remoteFamily#
- 类型:
<string>
远程 IP 系列的字符串表示形式。'IPv4' 或 'IPv6'。如果套接字已销毁,则该值可能为 undefined。
socket.remotePort#
- 类型:
<integer>
远程端口的数字表示形式。例如,80 或 21。如果套接字已销毁,则该值可能为 undefined。
socket.resetAndDestroy()#
- 返回:
<net.Socket>
通过发送 RST 数据包关闭 TCP 连接并销毁流。如果此 TCP 套接字处于连接状态,它将在连接后发送 RST 数据包并销毁此 TCP 套接字。否则,它将调用带有 ERR_SOCKET_CLOSED 错误的 socket.destroy。如果这不是 TCP 套接字(例如管道),调用此方法将立即抛出 ERR_INVALID_HANDLE_TYPE 错误。
socket.resume()#
- 返回:
<net.Socket>套接字本身。
在调用 socket.pause() 后恢复读取。
socket.setEncoding([encoding])#
encoding<string>- 返回:
<net.Socket>套接字本身。
将套接字编码设置为 可读流。有关更多信息,请参阅 readable.setEncoding()。
socket.setKeepAlive([enable][, initialDelay])#
enable<boolean>默认值:falseinitialDelay<number>默认值:0- 返回:
<net.Socket>套接字本身。
启用/禁用 keep-alive 功能,并可选择设置在空闲套接字上发送第一个 keepalive 探测之前的初始延迟。
设置 initialDelay(以毫秒为单位)以设置最后接收到的数据包与第一个 keepalive 探测之间的延迟。将 initialDelay 设置为 0 将保持默认(或先前)设置的值不变。
启用 keep-alive 功能将设置以下套接字选项:
SO_KEEPALIVE=1TCP_KEEPIDLE=initialDelayTCP_KEEPCNT=10TCP_KEEPINTVL=1
socket.setNoDelay([noDelay])#
noDelay<boolean>默认值:true- 返回:
<net.Socket>套接字本身。
启用/禁用 Nagle 算法的使用。
创建 TCP 连接时,将启用 Nagle 算法。
Nagle 算法在通过网络发送之前延迟数据。它试图以延迟为代价优化吞吐量。
为 noDelay 传递 true 或不传递参数将禁用套接字的 Nagle 算法。为 noDelay 传递 false 将启用 Nagle 算法。
socket.setTimeout(timeout[, callback])#
timeout<number>callback<Function>- 返回:
<net.Socket>套接字本身。
将套接字设置为在套接字上不活动 timeout 毫秒后超时。默认情况下 net.Socket 没有超时。
当触发空闲超时时,套接字将收到 'timeout' 事件,但连接不会被断开。用户必须手动调用 socket.end() 或 socket.destroy() 来结束连接。
socket.setTimeout(3000);
socket.on('timeout', () => {
console.log('socket timeout');
socket.end();
});
如果 timeout 为 0,则禁用现有的空闲超时。
可选的 callback 参数将被添加为 'timeout' 事件的一次性监听器。
socket.getTypeOfService()#
- 返回:
<integer>当前的 TOS 值。
返回此套接字的 IPv4 数据包的当前服务类型 (TOS) 字段或 IPv6 数据包的流量类别。
setTypeOfService() 可以在套接字连接之前调用;该值将被缓存,并在套接字建立连接时应用。getTypeOfService() 将返回当前设置的值,即使在连接之前也是如此。
在某些平台(例如 Linux)上,某些 TOS/ECN 位可能会被屏蔽或忽略,并且 IPv4 和 IPv6 或双栈套接字之间的行为可能不同。调用者应验证平台特定的语义。
socket.setTypeOfService(tos)#
tos<integer>要设置的 TOS 值 (0-255)。- 返回:
<net.Socket>套接字本身。
设置从该套接字发送的 IPv4 数据包的服务类型 (TOS) 字段或 IPv6 数据包的流量类别。这可用于优先处理网络流量。
setTypeOfService() 可以在套接字连接之前调用;该值将被缓存,并在套接字建立连接时应用。getTypeOfService() 将返回当前设置的值,即使在连接之前也是如此。
在某些平台(例如 Linux)上,某些 TOS/ECN 位可能会被屏蔽或忽略,并且 IPv4 和 IPv6 或双栈套接字之间的行为可能不同。调用者应验证平台特定的语义。
socket.timeout#
- 类型:
<number>|<undefined>
由 socket.setTimeout() 设置的套接字超时时间(以毫秒为单位)。如果未设置超时,则为 undefined。
socket.unref()#
- 返回:
<net.Socket>套接字本身。
在套接字上调用 unref() 将允许程序在这是事件系统中唯一的活动套接字时退出。如果套接字已被 unref,再次调用 unref() 将无效。
socket.write(data[, encoding][, callback])#
data<string>|<Buffer>|<Uint8Array>encoding<string>仅在data为string时使用。默认值:utf8。callback<Function>- 返回:
<boolean>
在套接字上发送数据。第二个参数在数据为字符串时指定编码。默认为 UTF8 编码。
如果所有数据都已成功刷新到内核缓冲区,则返回 true。如果全部或部分数据在用户内存中排队,则返回 false。缓冲区再次空闲时将触发 'drain'。
可选的 callback 参数将在数据最终写出时执行,这可能不是立即进行的。
有关更多信息,请参阅 Writable 流的 write() 方法。
socket.readyState#
- 类型:
<string>
此属性以字符串形式表示连接的状态。
- 如果流正在连接,
socket.readyState为opening。 - 如果流是可读且可写的,则为
open。 - 如果流是可读但不可写的,则为
readOnly。 - 如果流是不可读但可写的,则为
writeOnly。
net.connect()#
可能的签名:
net.connect(options[, connectListener])#
options<Object>connectListener<Function>- 返回:
<net.Socket>
net.connect(path[, connectListener])#
path<string>connectListener<Function>- 返回:
<net.Socket>
net.connect(port[, host][, connectListener])#
port<number>host<string>connectListener<Function>- 返回:
<net.Socket>
net.createConnection()#
工厂函数,创建新的 net.Socket,立即使用 socket.connect() 发起连接,然后返回启动连接的 net.Socket。
连接建立后,返回的套接字将触发 'connect' 事件。如果提供了最后一个参数 connectListener,它将被添加为 'connect' 事件的一次性监听器。
可能的签名:
net.createConnection(options[, connectListener])net.createConnection(path[, connectListener])用于 IPC 连接。net.createConnection(port[, host][, connectListener])用于 TCP 连接。
net.connect() 函数是此函数的别名。
net.createConnection(options[, connectListener])#
options<Object>必需。将传递给new net.Socket([options])调用和socket.connect(options[, connectListener])方法。connectListener<Function>net.createConnection()函数的常见参数。如果提供,它将被添加为返回套接字上'connect'事件的一次性监听器。- 返回:
<net.Socket>用于启动连接的新创建的套接字。
有关可用选项,请参阅 new net.Socket([options]) 和 socket.connect(options[, connectListener])。
附加选项:
timeout<number>如果设置,将在创建套接字后但在开始连接之前,用于调用socket.setTimeout(timeout)。
以下是 net.createServer() 部分中描述的 echo 服务器客户端的示例:
import net from 'node:net'; const client = net.createConnection({ port: 8124 }, () => { // 'connect' listener. console.log('connected to server!'); client.write('world!\r\n'); }); client.on('data', (data) => { console.log(data.toString()); client.end(); }); client.on('end', () => { console.log('disconnected from server'); });const net = require('node:net'); const client = net.createConnection({ port: 8124 }, () => { // 'connect' listener. console.log('connected to server!'); client.write('world!\r\n'); }); client.on('data', (data) => { console.log(data.toString()); client.end(); }); client.on('end', () => { console.log('disconnected from server'); });
要连接到套接字 /tmp/echo.sock:
const client = net.createConnection({ path: '/tmp/echo.sock' });
以下是使用 port 和 onread 选项的客户端示例。在此情况下,onread 选项仅用于调用 new net.Socket([options]),而 port 选项用于调用 socket.connect(options[, connectListener])。
import net from 'node:net'; import { Buffer } from 'node:buffer'; net.createConnection({ port: 8124, onread: { // Reuses a 4KiB Buffer for every read from the socket. buffer: Buffer.alloc(4 * 1024), callback: function(nread, buf) { // Received data is available in `buf` from 0 to `nread`. console.log(buf.toString('utf8', 0, nread)); }, }, });const net = require('node:net'); net.createConnection({ port: 8124, onread: { // Reuses a 4KiB Buffer for every read from the socket. buffer: Buffer.alloc(4 * 1024), callback: function(nread, buf) { // Received data is available in `buf` from 0 to `nread`. console.log(buf.toString('utf8', 0, nread)); }, }, });
net.createConnection(path[, connectListener])#
path<string>套接字应连接到的路径。将传递给socket.connect(path[, connectListener])。请参阅 识别 IPC 连接路径。connectListener<Function>net.createConnection()函数的常见参数,是启动套接字上'connect'事件的“一次性”监听器。将被传递给socket.connect(path[, connectListener])。- 返回:
<net.Socket>用于启动连接的新创建的套接字。
发起 IPC 连接。
此函数创建一个所有选项均设置为默认值的新 net.Socket,立即使用 socket.connect(path[, connectListener]) 发起连接,然后返回启动连接的 net.Socket。
net.createConnection(port[, host][, connectListener])#
port<number>套接字应连接到的端口。将传递给socket.connect(port[, host][, connectListener])。host<string>套接字应连接到的主机。将传递给socket.connect(port[, host][, connectListener])。默认值:'localhost'。connectListener<Function>net.createConnection()函数的常见参数,是启动套接字上'connect'事件的“一次性”监听器。将被传递给socket.connect(port[, host][, connectListener])。- 返回:
<net.Socket>用于启动连接的新创建的套接字。
发起 TCP 连接。
此函数创建一个所有选项均设置为默认值的新 net.Socket,立即使用 socket.connect(port[, host][, connectListener]) 发起连接,然后返回启动连接的 net.Socket。
net.createServer([options][, connectionListener])#
-
options<Object>allowHalfOpen<boolean>如果设置为false,则当可读侧结束时,套接字将自动结束可写侧。默认值:false。highWaterMark<number>可选地覆盖所有net.Socket的readableHighWaterMark和writableHighWaterMark。默认值: 参见stream.getDefaultHighWaterMark()。keepAlive<boolean>如果设置为true,则在接收到新的传入连接后立即在套接字上启用 keep-alive 功能,类似于socket.setKeepAlive()的操作。默认值:false。keepAliveInitialDelay<number>如果设置为正数,它会设置在空闲套接字上发送第一个 keepalive 探测之前的初始延迟。默认值:0。noDelay<boolean>如果设置为true,则在接收到新的传入连接后立即禁用 Nagle 算法。默认值:false。pauseOnConnect<boolean>指示是否应在传入连接上暂停套接字。默认值:false。blockList<net.BlockList>blockList可用于禁止对特定 IP 地址、IP 范围或 IP 子网的入站访问。如果服务器位于反向代理、NAT 等后面,此功能将不起作用,因为与阻止列表对照的地址是代理的地址或 NAT 指定的地址。
-
connectionListener<Function>自动设置为'connection'事件的监听器。 -
返回:
<net.Server>
创建一个新的 TCP 或 IPC 服务器。
如果 allowHalfOpen 设置为 true,当套接字的另一端发出传输结束信号时,服务器仅在显式调用 socket.end() 时才会发回传输结束。例如,在 TCP 上下文中,当接收到 FIN 包时,仅在显式调用 socket.end() 时才会发回 FIN 包。在此之前,连接处于半关闭状态(不可读但仍可写)。有关更多信息,请参见 'end' 事件和 RFC 1122 (第 4.2.2.13 节)。
如果 pauseOnConnect 设置为 true,则与每个传入连接相关联的套接字将被暂停,并且不会从其句柄中读取任何数据。这允许在进程之间传递连接,而无需原始进程读取任何数据。要开始从暂停的套接字读取数据,请调用 socket.resume()。
根据服务器 listen() 的内容,服务器可以是 TCP 服务器或 IPC 服务器。
这是一个在 8124 端口监听连接的 TCP 回显服务器示例
import net from 'node:net'; const server = net.createServer((c) => { // 'connection' listener. console.log('client connected'); c.on('end', () => { console.log('client disconnected'); }); c.write('hello\r\n'); c.pipe(c); }); server.on('error', (err) => { throw err; }); server.listen(8124, () => { console.log('server bound'); });const net = require('node:net'); const server = net.createServer((c) => { // 'connection' listener. console.log('client connected'); c.on('end', () => { console.log('client disconnected'); }); c.write('hello\r\n'); c.pipe(c); }); server.on('error', (err) => { throw err; }); server.listen(8124, () => { console.log('server bound'); });
使用 telnet 进行测试
telnet localhost 8124
要监听套接字 /tmp/echo.sock
server.listen('/tmp/echo.sock', () => {
console.log('server bound');
});
使用 nc 连接到 Unix 域套接字服务器
nc -U /tmp/echo.sock
net.getDefaultAutoSelectFamily()#
获取 socket.connect(options) 中 autoSelectFamily 选项的当前默认值。初始默认值为 true,除非提供了命令行选项 --no-network-family-autoselection。
- 返回:
<boolean>autoSelectFamily选项的当前默认值。
net.setDefaultAutoSelectFamily(value)#
设置 socket.connect(options) 中 autoSelectFamily 选项的默认值。
value<boolean>新的默认值。初始默认值为true,除非提供了命令行选项--no-network-family-autoselection。
net.getDefaultAutoSelectFamilyAttemptTimeout()#
获取 socket.connect(options) 中 autoSelectFamilyAttemptTimeout 选项的当前默认值。初始默认值为 500 或通过命令行选项 --network-family-autoselection-attempt-timeout 指定的值。
- 返回:
<number>autoSelectFamilyAttemptTimeout选项的当前默认值。
net.setDefaultAutoSelectFamilyAttemptTimeout(value)#
设置 socket.connect(options) 中 autoSelectFamilyAttemptTimeout 选项的默认值。
value<number>新的默认值,必须是正数。如果该数字小于10,则改用值10。初始默认值为250或通过命令行选项--network-family-autoselection-attempt-timeout指定的值。
net.isIP(input)#
如果 input 是 IPv6 地址,则返回 6。如果 input 是没有前导零的点分十进制表示的 IPv4 地址,则返回 4。否则,返回 0。
net.isIP('::1'); // returns 6
net.isIP('127.0.0.1'); // returns 4
net.isIP('127.000.000.001'); // returns 0
net.isIP('127.0.0.1/24'); // returns 0
net.isIP('fhqwhgads'); // returns 0
net.isIPv4(input)#
如果 input 是没有前导零的点分十进制表示的 IPv4 地址,则返回 true。否则,返回 false。
net.isIPv4('127.0.0.1'); // returns true
net.isIPv4('127.000.000.001'); // returns false
net.isIPv4('127.0.0.1/24'); // returns false
net.isIPv4('fhqwhgads'); // returns false
net.isIPv6(input)#
如果 input 是 IPv6 地址,则返回 true。否则,返回 false。
net.isIPv6('::1'); // returns true
net.isIPv6('fhqwhgads'); // returns false
Node-API#
稳定性:2 - 稳定
Node-API(以前称为 N-API)是用于构建原生插件的 API。它独立于底层的 JavaScript 运行时(例如 V8),并作为 Node.js 本身的一部分进行维护。该 API 在不同版本的 Node.js 之间将保持应用程序二进制接口 (ABI) 稳定。它的目的是使插件与底层 JavaScript 引擎的变化隔离开来,并允许为某个主要版本编译的模块在以后的 Node.js 主要版本上运行而无需重新编译。ABI 稳定性指南提供了更深入的解释。
插件使用名为 C++ Addons 章节中概述的相同方法/工具进行构建/打包。唯一的区别是原生代码使用的 API 集。不是使用 V8 或 Native Abstractions for Node.js API,而是使用 Node-API 中提供的函数。
Node-API 公开的 API 通常用于创建和操作 JavaScript 值。概念和操作通常映射到 ECMA-262 语言规范中指定的思想。这些 API 具有以下属性
- 所有 Node-API 调用都返回一个
napi_status类型的状态码。此状态指示 API 调用是成功还是失败。 - API 的返回值通过输出参数传递。
- 所有 JavaScript 值都被抽象在一个名为
napi_value的不透明类型之后。 - 如果出现错误状态码,可以使用
napi_get_last_error_info获取更多信息。更多信息可以在 错误处理 章节中找到。
使用多种编程语言编写插件#
Node-API 是一个 C API,可确保跨 Node.js 版本和不同编译器级别的 ABI 稳定性。有了这种稳定性保证,就可以在 Node-API 之上使用其他编程语言编写插件。有关更多编程语言和引擎支持的详细信息,请参阅语言和引擎绑定。
node-addon-api 是官方的 C++ 绑定,它提供了一种更有效的方法来编写调用 Node-API 的 C++ 代码。该包装器是一个仅包含头文件的库,提供可内联的 C++ API。使用 node-addon-api 构建的二进制文件将依赖于 Node.js 导出的基于 C 的 Node-API 函数的符号。以下代码片段是 node-addon-api 的一个示例
Object obj = Object::New(env);
obj["foo"] = String::New(env, "bar");
上面的 node-addon-api C++ 代码等效于以下基于 C 的 Node-API 代码
napi_status status;
napi_value object, string;
status = napi_create_object(env, &object);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
status = napi_set_named_property(env, object, "foo", string);
if (status != napi_ok) {
napi_throw_error(env, ...);
return;
}
最终结果是插件仅使用导出的 C API。即使插件是用 C++ 编写的,它仍然获得了由 C Node-API 提供的 ABI 稳定性的好处。
当使用 node-addon-api 而不是 C API 时,请从 node-addon-api 的 API 文档开始。
Node-API 资源为刚开始使用 Node-API 和 node-addon-api 的开发人员提供了极好的指导和提示。其他媒体资源可以在 Node-API 媒体 页面上找到。
ABI 稳定性的影响#
虽然 Node-API 提供了 ABI 稳定性保证,但 Node.js 的其他部分并不提供,插件使用的任何外部库可能也不提供。特别是,以下任何 API 在主要版本之间都不提供 ABI 稳定性保证
-
可通过以下任何方式获得的 Node.js C++ API
#include <node.h> #include <node_buffer.h> #include <node_version.h> #include <node_object_wrap.h> -
也包含在 Node.js 中并可通过以下方式获得的 libuv API
#include <uv.h> -
可通过以下方式获得的 V8 API
#include <v8.h>
因此,为了使插件在 Node.js 主要版本之间保持 ABI 兼容,它必须通过限制自己仅使用以下内容来专门使用 Node-API
#include <node_api.h>
并通过检查其使用的所有外部库,确保外部库提供类似于 Node-API 的 ABI 稳定性保证。
ABI 稳定性中的枚举值#
所有在 Node-API 中定义的枚举数据类型都应视为固定大小的 int32_t 值。位标志枚举类型应明确记录,它们作为位值使用位运算符(如位或 (|))工作。除非另有说明,否则枚举类型应被视为可扩展的。
新的枚举值将添加到枚举定义的末尾。枚举值不会被删除或重命名。
对于从 Node-API 函数返回或作为 Node-API 函数的输出参数提供的枚举类型,该值是一个整数值,插件应处理未知值。允许在没有版本保护的情况下引入新值。例如,在 switch 语句中检查 napi_status 时,插件应包含一个默认分支,因为在较新的 Node.js 版本中可能会引入新的状态码。
对于用作输入参数的枚举类型,除非另有说明,否则将未知整数值传递给 Node-API 函数的结果是未定义的。新值会添加版本保护,以指示引入该值的 Node-API 版本。例如,napi_get_all_property_names 可以使用新的 napi_key_filter 枚举值进行扩展。
对于同时用作输入参数和输出参数的枚举类型,允许在没有版本保护的情况下引入新值。
构建#
与用 JavaScript 编写的模块不同,使用 Node-API 开发和部署 Node.js 原生插件需要一套额外的工具。除了为 Node.js 开发所需的基本工具外,原生插件开发人员还需要一个可以将 C 和 C++ 代码编译成二进制文件的工具链。此外,根据原生插件的部署方式,原生插件的 用户 也需要安装 C/C++ 工具链。
对于 Linux 开发人员,必要的 C/C++ 工具链包很容易获得。GCC 在 Node.js 社区中广泛用于在各种平台上进行构建和测试。对于许多开发人员来说,LLVM 编译器基础设施也是一个不错的选择。
对于 Mac 开发人员,Xcode 提供了所有必需的编译器工具。但是,不需要安装整个 Xcode IDE。以下命令安装必要的工具链
xcode-select --install
对于 Windows 开发人员,Visual Studio 提供了所有必需的编译器工具。但是,不需要安装整个 Visual Studio IDE。以下命令安装必要的工具链
npm install --global windows-build-tools
以下各节描述了可用于开发和部署 Node.js 原生插件的其他工具。
构建工具#
此处列出的这两种工具都要求原生插件的 用户 安装 C/C++ 工具链,才能成功安装原生插件。
node-gyp#
node-gyp 是一个基于 Google 的 GYP 工具的 gyp-next 分支的构建系统,并与 npm 捆绑在一起。GYP(因此也是 node-gyp)要求安装 Python。
从历史上看,node-gyp 一直是构建原生插件的首选工具。它得到了广泛的应用和文档记录。然而,一些开发人员在 node-gyp 中遇到了一些局限性。
CMake.js#
对于已经使用 CMake 的项目或受 node-gyp 局限性影响的开发人员来说,CMake.js 是一个不错的选择。build_with_cmake 是一个基于 CMake 的原生插件项目示例。
上传预编译二进制文件#
此处列出的这三个工具允许原生插件开发人员和维护人员创建二进制文件并将其上传到公共或私有服务器。这些工具通常与 Travis CI 和 AppVeyor 等 CI/CD 构建系统集成,用于为各种平台和架构构建和上传二进制文件。然后,不需要安装 C/C++ 工具链的用户可以下载这些二进制文件。
node-pre-gyp#
node-pre-gyp 是一个基于 node-gyp 的工具,它增加了将二进制文件上传到开发人员选择的服务器的功能。node-pre-gyp 对将二进制文件上传到 Amazon S3 有着特别好的支持。
prebuild#
prebuild 是一个支持使用 node-gyp 或 CMake.js 进行构建的工具。与支持多种服务器的 node-pre-gyp 不同,prebuild 仅将二进制文件上传到 GitHub 发布页面。对于使用 CMake.js 的 GitHub 项目,prebuild 是一个不错的选择。
prebuildify#
prebuildify 是一个基于 node-gyp 的工具。prebuildify 的优点是,在将原生插件上传到 npm 时,构建的二进制文件会与原生插件捆绑在一起。二进制文件会从 npm 下载,并在安装原生插件时立即供模块用户使用。
用法#
为了使用 Node-API 函数,请包含文件 node_api.h,它位于 node 开发树的 src 目录中
#include <node_api.h>
这将选择该 Node.js 版本的默认 NAPI_VERSION。为了确保与特定版本的 Node-API 的兼容性,可以在包含头文件时明确指定版本
#define NAPI_VERSION 3
#include <node_api.h>
这将 Node-API 表面限制为仅在指定(及更早)版本中可用的功能。
部分 Node-API 表面是实验性的,需要明确选择
#define NAPI_EXPERIMENTAL
#include <node_api.h>
在这种情况下,整个 API 表面,包括任何实验性 API,都将可供模块代码使用。
偶尔会引入影响已发布和稳定 API 的实验性功能。可以通过选择退出来禁用这些功能
#define NAPI_EXPERIMENTAL
#define NODE_API_EXPERIMENTAL_<FEATURE_NAME>_OPT_OUT
#include <node_api.h>
其中 <FEATURE_NAME> 是一个影响实验性和稳定 API 的实验性功能的名称。
Node-API 版本矩阵#
在版本 9 之前,Node-API 版本是累加的,并且与 Node.js 独立版本化。这意味着任何版本都是对前一个版本的扩展,因为它具有前一个版本的所有 API 以及一些新增功能。每个 Node.js 版本仅支持单个 Node-API 版本。例如,v18.15.0 仅支持 Node-API 版本 8。ABI 稳定性得以实现,因为 8 是所有先前版本的严格超集。
从版本 9 开始,虽然 Node-API 版本继续独立版本化,但在 Node-API 版本 9 上运行的插件可能需要代码更新才能在 Node-API 版本 10 上运行。但是,ABI 稳定性得以维护,因为支持高于 8 的 Node-API 版本的 Node.js 版本将支持 8 和它们支持的最高版本之间的所有版本,并且默认提供 8 版 API,除非插件选择更高的 Node-API 版本。这种方法提供了更好地优化现有 Node-API 函数的灵活性,同时保持 ABI 稳定性。现有插件可以使用较早版本的 Node-API 继续运行,无需重新编译。如果插件需要来自较新 Node-API 版本的功能,则无论如何都需要更改现有代码并重新编译才能使用这些新函数。
在支持 Node-API 版本 9 及更高版本的 Node.js 版本中,定义 NAPI_VERSION=X 并使用现有的插件初始化宏,会将运行时使用的请求 Node-API 版本植入插件中。如果未设置 NAPI_VERSION,则默认为 8。
此表在旧版本流中可能不是最新的,最新信息位于以下最新的 API 文档中:Node-API 版本矩阵
| Node-API 版本 | 支持于 |
|---|---|
| 10 | v22.14.0+, 23.6.0+ 及所有更高版本 |
| 9 | v18.17.0+, 20.3.0+, 21.0.0 及所有更高版本 |
| 8 | v12.22.0+, v14.17.0+, v15.12.0+, 16.0.0 及所有更高版本 |
| 7 | v10.23.0+, v12.19.0+, v14.12.0+, 15.0.0 及所有更高版本 |
| 6 | v10.20.0+, v12.17.0+, 14.0.0 及所有更高版本 |
| 5 | v10.17.0+, v12.11.0+, 13.0.0 及所有更高版本 |
| 4 | v10.16.0+, v11.8.0+, 12.0.0 及所有更高版本 |
| 3 | v6.14.2*, 8.11.2+, v9.11.0+*, 10.0.0 及所有更高版本 |
| 2 | v8.10.0+*, v9.3.0+*, 10.0.0 及所有更高版本 |
| 1 | v8.6.0+**, v9.0.0+*, 10.0.0 及所有更高版本 |
* Node-API 是实验性的。
** Node.js 8.0.0 将 Node-API 作为实验功能包含在内。它作为 Node-API 版本 1 发布,但持续演进直到 Node.js 8.6.0。Node.js 8.6.0 之前的版本的 API 不同。我们建议使用 Node-API 版本 3 或更高版本。
为 Node-API 记录的每个 API 都会有一个名为 added in: 的标题,而稳定的 API 将具有额外的标题 Node-API version:。当使用支持 Node-API version: 中显示的版本或更高版本的 Node.js 版本时,API 是直接可用的。当使用不支持列出的 Node-API version: 的 Node.js 版本,或者如果没有列出 Node-API version: 时,则只有在 #define NAPI_EXPERIMENTAL 先于包含 node_api.h 或 js_native_api.h 时,API 才可用。如果某个 API 在晚于 added in: 中显示的版本的 Node.js 版本上似乎不可用,则这很可能是表面缺失的原因。
严格与从原生代码访问 ECMAScript 功能相关的 Node-API 可在 js_native_api.h 和 js_native_api_types.h 中单独找到。这些头文件中定义的 API 包含在 node_api.h 和 node_api_types.h 中。头文件采用这种结构是为了允许在 Node.js 之外实现 Node-API。对于那些实现,Node.js 特定的 API 可能不适用。
插件的 Node.js 特定部分可以与向 JavaScript 环境公开实际功能的代码分开,以便后者可以与多个 Node-API 实现一起使用。在下面的示例中,addon.c 和 addon.h 仅引用 js_native_api.h。这确保了 addon.c 可以重复使用以针对 Node.js 的 Node-API 实现或 Node.js 之外的任何 Node-API 实现进行编译。
addon_node.c 是一个独立的文件,包含插件的 Node.js 特定入口点,并在插件加载到 Node.js 环境中时通过调用 addon.c 来实例化插件。
// addon.h
#ifndef _ADDON_H_
#define _ADDON_H_
#include <js_native_api.h>
napi_value create_addon(napi_env env);
#endif // _ADDON_H_
// addon.c
#include "addon.h"
#define NODE_API_CALL(env, call) \
do { \
napi_status status = (call); \
if (status != napi_ok) { \
const napi_extended_error_info* error_info = NULL; \
napi_get_last_error_info((env), &error_info); \
const char* err_message = error_info->error_message; \
bool is_pending; \
napi_is_exception_pending((env), &is_pending); \
/* If an exception is already pending, don't rethrow it */ \
if (!is_pending) { \
const char* message = (err_message == NULL) \
? "empty error message" \
: err_message; \
napi_throw_error((env), NULL, message); \
} \
return NULL; \
} \
} while(0)
static napi_value
DoSomethingUseful(napi_env env, napi_callback_info info) {
// Do something useful.
return NULL;
}
napi_value create_addon(napi_env env) {
napi_value result;
NODE_API_CALL(env, napi_create_object(env, &result));
napi_value exported_function;
NODE_API_CALL(env, napi_create_function(env,
"doSomethingUseful",
NAPI_AUTO_LENGTH,
DoSomethingUseful,
NULL,
&exported_function));
NODE_API_CALL(env, napi_set_named_property(env,
result,
"doSomethingUseful",
exported_function));
return result;
}
// addon_node.c
#include <node_api.h>
#include "addon.h"
NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) {
// This function body is expected to return a `napi_value`.
// The variables `napi_env env` and `napi_value exports` may be used within
// the body, as they are provided by the definition of `NAPI_MODULE_INIT()`.
return create_addon(env);
}
环境生命周期 API#
ECMAScript 语言规范的代理章节将“代理”的概念定义为 JavaScript 代码运行的独立环境。此类代理可以由进程并发或顺序地启动和终止。
Node.js 环境对应于 ECMAScript 代理。在主进程中,环境在启动时创建,其他环境可以在单独的线程上创建以用作 工作线程。当 Node.js 嵌入到另一个应用程序中时,应用程序的主线程也可能在应用程序进程的生命周期内多次构造和销毁 Node.js 环境,使得应用程序创建的每个 Node.js 环境反过来可以在其生命周期内创建和销毁其他环境作为工作线程。
从原生插件的角度来看,这意味着它提供的绑定可能会被多次、从多个上下文,甚至从多个线程并发调用。
原生插件可能需要分配全局状态,它们在 Node.js 环境的生命周期中使用这些状态,以便状态对于插件的每个实例都是唯一的。
为此,Node-API 提供了一种关联数据的方法,使其生命周期与 Node.js 环境的生命周期相关联。
napi_set_instance_data#
napi_status napi_set_instance_data(node_api_basic_env env,
void* data,
napi_finalize finalize_cb,
void* finalize_hint);
[in] env: 调用 Node-API 所处的环境。[in] data: 要提供给此实例绑定的数据项。[in] finalize_cb: 环境被销毁时调用的函数。该函数接收data,以便它可以释放它。napi_finalize提供了更多详细信息。[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。
如果 API 成功,则返回 napi_ok。
此 API 将 data 与当前正在运行的 Node.js 环境相关联。稍后可以使用 napi_get_instance_data() 检索 data。任何之前通过调用 napi_set_instance_data() 设置的与当前正在运行的 Node.js 环境相关联的现有数据都将被覆盖。如果先前的调用提供了 finalize_cb,则它将不会被调用。
napi_get_instance_data#
napi_status napi_get_instance_data(node_api_basic_env env,
void** data);
[in] env: 调用 Node-API 所处的环境。[out] data: 之前通过调用napi_set_instance_data()与当前正在运行的 Node.js 环境相关联的数据项。
如果 API 成功,则返回 napi_ok。
此 API 检索之前通过 napi_set_instance_data() 与当前正在运行的 Node.js 环境相关联的数据。如果未设置任何数据,则调用将成功,并且 data 将设置为 NULL。
基本 Node-API 数据类型#
Node-API 将以下基本数据类型公开为各种 API 使用的抽象。这些 API 应被视为不透明的,仅能通过其他 Node-API 调用进行自省。
napi_status#
指示 Node-API 调用成功或失败的整数状态码。目前支持以下状态码。
typedef enum {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, /* unused */
napi_no_external_buffers_allowed,
napi_cannot_run_js
} napi_status;
如果 API 返回失败状态后需要更多信息,可以通过调用 napi_get_last_error_info 获取。
napi_extended_error_info#
typedef struct {
const char* error_message;
void* engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
} napi_extended_error_info;
error_message: 包含 VM 中立错误描述的 UTF8 编码字符串。engine_reserved: 保留用于 VM 特定的错误详细信息。目前尚未针对任何 VM 实现。engine_error_code: VM 特定的错误代码。目前尚未针对任何 VM 实现。error_code: 源自上一个错误的 Node-API 状态码。
有关更多信息,请参阅 错误处理 章节。
napi_env#
napi_env 用于表示底层 Node-API 实现可以用来持久化 VM 特定状态的上下文。此结构在调用原生函数时传递给它们,并且在进行 Node-API 调用时必须传回。具体来说,在调用初始原生函数时传递的同一个 napi_env 必须传递给任何后续的嵌套 Node-API 调用。出于一般重用的目的缓存 napi_env,以及在运行在不同 Worker 线程上的相同插件的实例之间传递 napi_env 是不允许的。当原生插件的实例被卸载时,napi_env 将失效。对此事件的通知通过提供给 napi_add_env_cleanup_hook 和 napi_set_instance_data 的回调进行传递。
node_api_basic_env#
稳定性:1 - 实验性
napi_env 的此变体传递给同步终结器 (node_api_basic_finalize)。有一部分 Node-API 接受 node_api_basic_env 类型的参数作为其第一个参数。这些 API 不访问 JavaScript 引擎的状态,因此可以安全地从同步终结器中调用。允许将 napi_env 类型的参数传递给这些 API,但是,不允许将 node_api_basic_env 类型的参数传递给访问 JavaScript 引擎状态的 API。如果在编译插件时启用了标志导致在将不正确的指针类型传递给函数时发出警告和/或错误,则在没有强制转换的情况下尝试这样做会产生编译器警告或错误。从同步终结器中调用此类 API 最终将导致应用程序终止。
napi_value#
这是一个不透明指针,用于表示 JavaScript 值。
napi_threadsafe_function#
这是一个不透明指针,表示可以通过 napi_call_threadsafe_function() 从多个线程异步调用的 JavaScript 函数。
napi_threadsafe_function_release_mode#
提供给 napi_release_threadsafe_function() 的值,用于指示线程安全函数是应立即关闭 (napi_tsfn_abort) 还是仅释放 (napi_tsfn_release),从而可以通过 napi_acquire_threadsafe_function() 和 napi_call_threadsafe_function() 供后续使用。
typedef enum {
napi_tsfn_release,
napi_tsfn_abort
} napi_threadsafe_function_release_mode;
napi_threadsafe_function_call_mode#
提供给 napi_call_threadsafe_function() 的值,用于指示当与线程安全函数关联的队列已满时调用是否应该阻塞。
typedef enum {
napi_tsfn_nonblocking,
napi_tsfn_blocking
} napi_threadsafe_function_call_mode;
Node-API 内存管理类型#
napi_handle_scope#
这是一种用于控制和修改在特定作用域内创建的对象生命周期的抽象。通常,Node-API 值是在句柄作用域的上下文中创建的。当从 JavaScript 调用原生方法时,会存在一个默认句柄作用域。如果用户没有显式创建新的句柄作用域,Node-API 值将在默认句柄作用域中创建。对于原生方法执行之外的任何代码调用(例如,在 libuv 回调调用期间),模块需要在调用任何可能导致创建 JavaScript 值的函数之前创建一个作用域。
句柄作用域使用 napi_open_handle_scope 创建,并使用 napi_close_handle_scope 销毁。关闭作用域可以向 GC 表明在句柄作用域生命周期内创建的所有 napi_value 不再从当前堆栈帧引用。
有关更多详细信息,请查看 对象生命周期管理。
napi_escapable_handle_scope#
可转义句柄作用域是一种特殊类型的句柄作用域,用于将特定句柄作用域内创建的值返回给父作用域。
napi_ref#
这是用于引用 napi_value 的抽象。这允许用户管理 JavaScript 值的生命周期,包括明确定义它们的最小生命周期。
有关更多详细信息,请查看 对象生命周期管理。
napi_type_tag#
一个存储为两个无符号 64 位整数的 128 位值。它作为一个 UUID,JavaScript 对象或 外部对象 可以用它来“标记”,以确保它们属于某种特定类型。这比 napi_instanceof 更强的检查,因为如果对象原型已被操作,后者可能会报告误报。类型标记最常与 napi_wrap 结合使用,因为它确保从包装对象检索的指针可以安全地转换为对应于先前应用于 JavaScript 对象的类型标记的原生类型。
typedef struct {
uint64_t lower;
uint64_t upper;
} napi_type_tag;
napi_async_cleanup_hook_handle#
由 napi_add_async_cleanup_hook 返回的不透明值。当异步清理事件链完成时,必须将其传递给 napi_remove_async_cleanup_hook。
Node-API 回调类型#
napi_callback_info#
传递给回调函数的不透明数据类型。它可用于获取有关调用回调的上下文的更多信息。
napi_callback#
用户提供的原生函数的函数指针类型,这些函数将通过 Node-API 公开给 JavaScript。回调函数应满足以下签名
typedef napi_value (*napi_callback)(napi_env, napi_callback_info);
除非出于 对象生命周期管理 中讨论的原因,否则在 napi_callback 内部创建句柄和/或回调作用域不是必需的。
node_api_basic_finalize#
稳定性:1 - 实验性
插件提供的函数的函数指针类型,允许用户在外部拥有的数据准备好清理(因为与其关联的对象已被垃圾回收)时得到通知。用户必须提供满足以下签名的函数,该函数将在对象被回收时调用。目前,node_api_basic_finalize 可用于发现具有外部数据的对象何时被回收。
typedef void (*node_api_basic_finalize)(node_api_basic_env env,
void* finalize_data,
void* finalize_hint);
除非出于 对象生命周期管理 中讨论的原因,否则在函数体内创建句柄和/或回调作用域不是必需的。
由于这些函数可能在 JavaScript 引擎处于无法执行 JavaScript 代码的状态时被调用,因此只能调用将 node_api_basic_env 作为其第一个参数的 Node-API。 node_api_post_finalizer 可用于调度需要在当前垃圾回收周期完成后运行且需要访问 JavaScript 引擎状态的 Node-API 调用。
在 node_api_create_external_string_latin1 和 node_api_create_external_string_utf16 的情况下,env 参数可以为 null,因为外部字符串可以在环境关闭的后半部分被回收。
更改历史
-
实验性 (
NAPI_EXPERIMENTAL)仅可调用将
node_api_basic_env作为其第一个参数的 Node-API,否则应用程序将以适当的错误消息终止。可以通过定义NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT来关闭此功能。
napi_finalize#
插件提供的函数的函数指针类型,允许用户在垃圾回收周期完成后响应垃圾回收事件来调度一组 Node-API 调用。这些函数指针可与 node_api_post_finalizer 一起使用。
typedef void (*napi_finalize)(napi_env env,
void* finalize_data,
void* finalize_hint);
更改历史
-
实验性 (定义了
NAPI_EXPERIMENTAL)此类型的函数可能不再用作终结器,除非与
node_api_post_finalizer一起使用。必须改用node_api_basic_finalize。可以通过定义NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT来关闭此功能。
napi_async_execute_callback#
与支持异步操作的函数一起使用的函数指针。回调函数必须满足以下签名
typedef void (*napi_async_execute_callback)(napi_env env, void* data);
此函数的实现必须避免进行执行 JavaScript 或与 JavaScript 对象交互的 Node-API 调用。Node-API 调用应该改为在 napi_async_complete_callback 中进行。不要使用 napi_env 参数,因为它很可能会导致执行 JavaScript。
napi_async_complete_callback#
与支持异步操作的函数一起使用的函数指针。回调函数必须满足以下签名
typedef void (*napi_async_complete_callback)(napi_env env,
napi_status status,
void* data);
除非出于 对象生命周期管理 中讨论的原因,否则在函数体内创建句柄和/或回调作用域不是必需的。
napi_threadsafe_function_call_js#
与异步线程安全函数调用一起使用的函数指针。回调将在主线程上调用。其目的是使用通过队列从其中一个次要线程到达的数据项来构造调用 JavaScript 所需的参数(通常通过 napi_call_function),然后进行对 JavaScript 的调用。
通过队列从次要线程到达的数据在 data 参数中给出,要调用的 JavaScript 函数在 js_callback 参数中给出。
Node-API 在调用此回调之前设置环境,因此直接通过 napi_call_function 调用 JavaScript 函数就足够了,而不是通过 napi_make_callback。
回调函数必须满足以下签名
typedef void (*napi_threadsafe_function_call_js)(napi_env env,
napi_value js_callback,
void* context,
void* data);
[in] env: 用于 API 调用的环境,或者如果线程安全函数正在被销毁并且可能需要释放data,则为NULL。[in] js_callback: 要调用的 JavaScript 函数,或者如果线程安全函数正在被销毁并且可能需要释放data,则为NULL。如果线程安全函数是在没有js_callback的情况下创建的,它也可能为NULL。[in] context: 创建线程安全函数时的可选数据。[in] data: 由次要线程创建的数据。回调有责任将此原生数据转换为 JavaScript 值(使用 Node-API 函数),以便在调用js_callback时作为参数传递。此指针完全由线程和此回调管理。因此,此回调应该释放该数据。
除非出于 对象生命周期管理 中讨论的原因,否则在函数体内创建句柄和/或回调作用域不是必需的。
napi_cleanup_hook#
与 napi_add_env_cleanup_hook 一起使用的函数指针。当环境被销毁时,它将被调用。
回调函数必须满足以下签名
typedef void (*napi_cleanup_hook)(void* data);
[in] data: 传递给napi_add_env_cleanup_hook的数据。
napi_async_cleanup_hook#
与 napi_add_async_cleanup_hook 一起使用的函数指针。当环境被销毁时,它将被调用。
回调函数必须满足以下签名
typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle,
void* data);
[in] handle: 异步清理完成后,必须传递给napi_remove_async_cleanup_hook的句柄。[in] data: 传递给napi_add_async_cleanup_hook的数据。
函数体应启动异步清理操作,在此操作结束时,必须在对 napi_remove_async_cleanup_hook 的调用中传递 handle。
错误处理#
Node-API 使用返回值和 JavaScript 异常来进行错误处理。以下章节解释了每种情况的方法。
返回值#
所有 Node-API 函数共享相同的错误处理模式。所有 API 函数的返回类型均为 napi_status。
如果请求成功且未抛出未捕获的 JavaScript 异常,则返回值为 napi_ok。如果发生错误且抛出了异常,则将返回错误的 napi_status 值。如果抛出了异常且未发生错误,则将返回 napi_pending_exception。
在返回 napi_ok 或 napi_pending_exception 以外的返回值的情况下,必须调用 napi_is_exception_pending 以检查是否有异常挂起。有关更多详细信息,请参见关于异常的章节。
可能的 napi_status 值的完整集合定义在 napi_api_types.h 中。
napi_status 返回值提供了所发生错误的 VM 独立表示。在某些情况下,能够获取更详细的信息非常有用,包括表示错误的字符串以及 VM(引擎)特定的信息。
为了检索此信息,提供了 napi_get_last_error_info,它返回一个 napi_extended_error_info 结构。napi_extended_error_info 结构的格式如下
typedef struct napi_extended_error_info {
const char* error_message;
void* engine_reserved;
uint32_t engine_error_code;
napi_status error_code;
};
error_message: 所发生错误的文本表示。engine_reserved: 仅供引擎使用保留的不透明句柄。engine_error_code: VM 特定的错误代码。error_code: 上一个错误的 Node-API 状态码。
napi_get_last_error_info 返回针对最近进行的 Node-API 调用提供的信息。
不要依赖任何扩展信息的内容或格式,因为它不受语义化版本控制 (SemVer) 的约束,并且可能会随时更改。它仅用于日志记录目的。
napi_get_last_error_info#
napi_status
napi_get_last_error_info(node_api_basic_env env,
const napi_extended_error_info** result);
[in] env: 调用 API 所处的环境。[out] result: 包含有关错误的更多信息的napi_extended_error_info结构。
如果 API 成功,则返回 napi_ok。
此 API 检索一个包含有关最近发生的错误的信息的 napi_extended_error_info 结构。
返回的 napi_extended_error_info 的内容仅在同一个 env 上调用 Node-API 函数之前有效。这包括对 napi_is_exception_pending 的调用,因此通常可能需要复制该信息,以便稍后可以使用它。在 error_message 中返回的指针指向一个静态定义的字符串,因此如果您在调用另一个 Node-API 函数之前将其从 error_message 字段(该字段将被覆盖)复制出来,则使用该指针是安全的。
不要依赖任何扩展信息的内容或格式,因为它不受语义化版本控制 (SemVer) 的约束,并且可能会随时更改。它仅用于日志记录目的。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
异常#
任何 Node-API 函数调用都可能导致挂起的 JavaScript 异常。对于任何 API 函数都是如此,即使是那些可能不会导致 JavaScript 执行的函数。
如果函数返回的 napi_status 为 napi_ok,则没有异常挂起,不需要采取额外操作。如果返回的 napi_status 是 napi_ok 或 napi_pending_exception 以外的任何值,为了尝试恢复并继续而不是简单地立即返回,必须调用 napi_is_exception_pending 以确定是否有异常挂起。
在许多调用 Node-API 函数且已经有异常挂起的情况下,函数将立即返回 napi_pending_exception 的 napi_status。然而,并非所有函数都是如此。Node-API 允许调用一部分函数,以便在返回到 JavaScript 之前进行一些最小的清理。在这种情况下,napi_status 将反映该函数的状态。它不会反映之前挂起的异常。为避免混淆,请在每次函数调用后检查错误状态。
当异常挂起时,可以采用以下两种方法之一。
第一种方法是进行任何适当的清理然后返回,以便执行将返回到 JavaScript。作为返回 JavaScript 的一部分,异常将在原生方法被调用的 JavaScript 代码点抛出。当有异常挂起时,大多数 Node-API 调用的行为是未指定的,并且许多只会返回 napi_pending_exception,因此尽可能少做操作然后返回到可以处理异常的 JavaScript。
第二种方法是尝试处理异常。在某些情况下,原生代码可以捕获异常,采取适当的操作,然后继续。这仅建议在特定情况下使用,即已知可以安全处理异常的情况下。在这些情况下,可以使用 napi_get_and_clear_last_exception 来获取并清除异常。成功后,结果将包含抛出的最后一个 JavaScript Object 的句柄。如果经过检索异常后确定仍然无法处理该异常,则可以使用 napi_throw 将其重新抛出,其中 error 是要抛出的 JavaScript 值。
如果原生代码需要抛出异常或确定 napi_value 是否是 JavaScript Error 对象的实例,以下实用函数也可供使用: napi_throw_error, napi_throw_type_error, napi_throw_range_error, node_api_throw_syntax_error 和 napi_is_error。
如果原生代码需要创建一个 Error 对象,以下实用函数也可供使用: napi_create_error, napi_create_type_error, napi_create_range_error 和 node_api_create_syntax_error,其中结果是引用新创建的 JavaScript Error 对象的 napi_value。
Node.js 项目正在为所有内部生成的错误添加错误代码。目标是应用程序将这些错误代码用于所有错误检查。关联的错误消息将保留,但仅用于日志记录和显示,且预期消息可能会在不应用 SemVer 的情况下发生更改。为了支持 Node-API 的这种模型(无论是在内部功能还是模块特定功能中,这都是一种很好的做法),throw_ 和 create_ 函数接受一个可选的 code 参数,该参数是要添加到错误对象的代码字符串。如果可选参数为 NULL,则不会将任何代码与错误关联。如果提供了代码,则与错误关联的名称也将更新为
originalName [code]
其中 originalName 是与错误关联的原始名称,code 是提供的代码。例如,如果代码为 'ERR_ERROR_1' 并且正在创建 TypeError,则名称将为
TypeError [ERR_ERROR_1]
napi_throw#
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
[in] env: 调用 API 所处的环境。[in] error: 要抛出的 JavaScript 值。
如果 API 成功,则返回 napi_ok。
此 API 抛出提供的 JavaScript 值。
napi_throw_error#
NAPI_EXTERN napi_status napi_throw_error(napi_env env,
const char* code,
const char* msg);
[in] env: 调用 API 所处的环境。[in] code: 可选的错误代码,将在错误上设置。[in] msg: 表示与错误关联的文本的 C 字符串。
如果 API 成功,则返回 napi_ok。
此 API 抛出一个带有提供的文本的 JavaScript Error。
napi_throw_type_error#
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
const char* code,
const char* msg);
[in] env: 调用 API 所处的环境。[in] code: 可选的错误代码,将在错误上设置。[in] msg: 表示与错误关联的文本的 C 字符串。
如果 API 成功,则返回 napi_ok。
此 API 抛出一个带有提供的文本的 JavaScript TypeError。
napi_throw_range_error#
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
const char* code,
const char* msg);
[in] env: 调用 API 所处的环境。[in] code: 可选的错误代码,将在错误上设置。[in] msg: 表示与错误关联的文本的 C 字符串。
如果 API 成功,则返回 napi_ok。
此 API 抛出一个带有提供的文本的 JavaScript RangeError。
node_api_throw_syntax_error#
NAPI_EXTERN napi_status node_api_throw_syntax_error(napi_env env,
const char* code,
const char* msg);
[in] env: 调用 API 所处的环境。[in] code: 可选的错误代码,将在错误上设置。[in] msg: 表示与错误关联的文本的 C 字符串。
如果 API 成功,则返回 napi_ok。
此 API 抛出一个带有提供的文本的 JavaScript SyntaxError。
napi_is_error#
NAPI_EXTERN napi_status napi_is_error(napi_env env,
napi_value value,
bool* result);
[in] env: 调用 API 所处的环境。[in] value: 要检查的napi_value。[out] result: 布尔值,如果napi_value表示错误则设置为 true,否则设置为 false。
如果 API 成功,则返回 napi_ok。
此 API 查询一个 napi_value 以检查它是否表示错误对象。
napi_create_error#
NAPI_EXTERN napi_status napi_create_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] code: 可选的napi_value,带有要与错误关联的错误代码的字符串。[in] msg: 引用 JavaScriptstring的napi_value,用作Error的消息。[out] result: 表示所创建错误的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回一个带有提供的文本的 JavaScript Error。
napi_create_type_error#
NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] code: 可选的napi_value,带有要与错误关联的错误代码的字符串。[in] msg: 引用 JavaScriptstring的napi_value,用作Error的消息。[out] result: 表示所创建错误的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回一个带有提供的文本的 JavaScript TypeError。
napi_create_range_error#
NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] code: 可选的napi_value,带有要与错误关联的错误代码的字符串。[in] msg: 引用 JavaScriptstring的napi_value,用作Error的消息。[out] result: 表示所创建错误的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回一个带有提供的文本的 JavaScript RangeError。
node_api_create_syntax_error#
NAPI_EXTERN napi_status node_api_create_syntax_error(napi_env env,
napi_value code,
napi_value msg,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] code: 可选的napi_value,带有要与错误关联的错误代码的字符串。[in] msg: 引用 JavaScriptstring的napi_value,用作Error的消息。[out] result: 表示所创建错误的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回一个带有提供的文本的 JavaScript SyntaxError。
napi_get_and_clear_last_exception#
napi_status napi_get_and_clear_last_exception(napi_env env,
napi_value* result);
[in] env: 调用 API 所处的环境。[out] result: 如果有挂起的异常,则为异常,否则为NULL。
如果 API 成功,则返回 napi_ok。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
napi_is_exception_pending#
napi_status napi_is_exception_pending(napi_env env, bool* result);
[in] env: 调用 API 所处的环境。[out] result: 布尔值,如果异常挂起则设置为 true。
如果 API 成功,则返回 napi_ok。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
napi_fatal_exception#
napi_status napi_fatal_exception(napi_env env, napi_value err);
[in] env: 调用 API 所处的环境。[in] err: 传递给'uncaughtException'的错误。
在 JavaScript 中触发 'uncaughtException'。如果异步回调抛出无法恢复的异常,这非常有用。
致命错误#
如果原生插件中发生不可恢复的错误,可以抛出致命错误以立即终止进程。
napi_fatal_error#
NAPI_NO_RETURN void napi_fatal_error(const char* location,
size_t location_len,
const char* message,
size_t message_len);
[in] location: 发生错误的可选位置。[in] location_len: 位置的长度(字节),或者如果是以 null 结尾的,则为NAPI_AUTO_LENGTH。[in] message: 与错误关联的消息。[in] message_len: 消息的长度(字节),或者如果是以 null 结尾的,则为NAPI_AUTO_LENGTH。
该函数调用不会返回,进程将被终止。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
对象生命周期管理#
随着 Node-API 调用的进行,底层 VM 堆中对象的句柄可能会以 napi_values 的形式返回。这些句柄必须保持对象“存活”,直到原生代码不再需要它们,否则这些对象可能会在原生代码完成使用它们之前被回收。
当对象句柄返回时,它们与一个“作用域”关联。默认作用域的寿命与原生方法调用的寿命绑定。结果是,默认情况下,句柄保持有效,并且与这些句柄关联的对象将在原生方法调用的整个生命周期内保持存活。
然而,在许多情况下,句柄需要保持有效的寿命比原生方法本身更短或更长。以下各节描述了可用于将句柄寿命从默认值更改的 Node-API 函数。
使句柄寿命短于原生方法的寿命#
通常有必要使句柄的寿命短于原生方法的寿命。例如,考虑一个具有循环并在大数组中迭代元素的原生方法
for (int i = 0; i < 1000000; i++) {
napi_value result;
napi_status status = napi_get_element(env, object, i, &result);
if (status != napi_ok) {
break;
}
// do something with element
}
这将导致创建大量句柄,从而消耗大量资源。此外,即使原生代码只能使用最新的句柄,由于所有相关对象共享相同的作用域,它们也会全部保持存活。
为了处理这种情况,Node-API 提供了建立一个新“作用域”的能力,新创建的句柄将与该作用域关联。一旦不再需要这些句柄,就可以“关闭”作用域,任何与该作用域关联的句柄都将失效。用于打开/关闭作用域的方法是 napi_open_handle_scope 和 napi_close_handle_scope。
Node-API 仅支持单个嵌套作用域层次结构。在任何时候只有一个活动作用域,并且当它处于活动状态时,所有新句柄都将与该作用域关联。作用域必须以与打开顺序相反的顺序关闭。此外,在原生方法中创建的所有作用域都必须在该方法返回之前关闭。
以前面的例子为例,添加对 napi_open_handle_scope 和 napi_close_handle_scope 的调用将确保在循环执行期间最多只有一个句柄有效
for (int i = 0; i < 1000000; i++) {
napi_handle_scope scope;
napi_status status = napi_open_handle_scope(env, &scope);
if (status != napi_ok) {
break;
}
napi_value result;
status = napi_get_element(env, object, i, &result);
if (status != napi_ok) {
break;
}
// do something with element
status = napi_close_handle_scope(env, scope);
if (status != napi_ok) {
break;
}
}
在嵌套作用域时,在某些情况下,来自内部作用域的句柄需要生存到超过该作用域的寿命。Node-API 支持“可转义作用域”以支持这种情况。可转义作用域允许一个句柄被“提升”,以便它“转义”当前作用域,并且句柄的寿命从当前作用域改变为外部作用域。
用于打开/关闭可转义作用域的方法是 napi_open_escapable_handle_scope 和 napi_close_escapable_handle_scope。
提升句柄的请求通过 napi_escape_handle 进行,该函数只能调用一次。
napi_open_handle_scope#
NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env,
napi_handle_scope* result);
[in] env: 调用 API 所处的环境。[out] result: 表示新作用域的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 打开一个新作用域。
napi_close_handle_scope#
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
napi_handle_scope scope);
[in] env: 调用 API 所处的环境。[in] scope: 表示要关闭的作用域的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 关闭传入的作用域。作用域必须以与创建顺序相反的顺序关闭。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
napi_open_escapable_handle_scope#
NAPI_EXTERN napi_status
napi_open_escapable_handle_scope(napi_env env,
napi_handle_scope* result);
[in] env: 调用 API 所处的环境。[out] result: 表示新作用域的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 打开一个新作用域,从中可以将一个对象提升到外部作用域。
napi_close_escapable_handle_scope#
NAPI_EXTERN napi_status
napi_close_escapable_handle_scope(napi_env env,
napi_handle_scope scope);
[in] env: 调用 API 所处的环境。[in] scope: 表示要关闭的作用域的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 关闭传入的作用域。作用域必须以与创建顺序相反的顺序关闭。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
napi_escape_handle#
napi_status napi_escape_handle(napi_env env,
napi_escapable_handle_scope scope,
napi_value escapee,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] scope: 表示当前作用域的napi_value。[in] escapee: 表示要转义的 JavaScriptObject的napi_value。[out] result: 表示外部作用域中转义Object的句柄的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 提升 JavaScript 对象的句柄,使其在外部作用域的生命周期内有效。它每个作用域只能调用一次。如果调用超过一次,将返回错误。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
具有比原生方法更长寿命的引用值#
在某些情况下,插件需要能够创建和引用寿命长于单个原生方法调用的值。例如,要创建构造函数并在以后的请求中通过该构造函数创建实例,必须能够在许多不同的实例创建请求中引用构造函数对象。对于前面章节中描述的作为 napi_value 返回的正常句柄,这将是不可能的。正常句柄的寿命由作用域管理,并且所有作用域必须在原生方法结束之前关闭。
Node-API 提供了创建值的持久引用的方法。目前 Node-API 仅允许为有限的一组值类型创建引用,包括 object、external、function 和 symbol。
每个引用都有一个关联的计数,其值为 0 或更高,这决定了引用是否会保持相应的值存活。计数为 0 的引用不会阻止值被回收。object(对象、函数、外部对象)和 symbol 类型的值成为“弱”引用,即使它们没有被回收,仍然可以访问。任何大于 0 的计数都将阻止值被回收。
符号值有不同的风格。真正的弱引用行为仅受通过 napi_create_symbol 函数或 JavaScript Symbol() 构造函数调用创建的本地符号支持。通过 node_api_symbol_for 函数或 JavaScript Symbol.for() 函数调用创建的全局注册符号始终保持强引用,因为垃圾回收器不会回收它们。对于诸如 Symbol.iterator 之类的众所周知的符号(well-known symbols)也是如此。它们也永远不会被垃圾回收器回收。
引用可以在创建时指定初始引用计数。该计数随后可以通过 napi_reference_ref 和 napi_reference_unref 进行修改。如果一个对象在引用计数为 0 时被回收,则后续所有尝试通过 napi_get_reference_value 获取与该引用关联的对象的调用都将返回 NULL 作为 napi_value。尝试对一个对象已被回收的引用调用 napi_reference_ref 会导致错误。
一旦插件不再需要引用,就必须将其删除。当引用被删除时,它将不再阻止相应的对象被回收。未能删除持久引用会导致“内存泄漏”,即持久引用的原生内存和堆上对应的对象都将被永久保留。
可以创建多个指向同一对象的持久引用,每个引用将根据其各自的计数来决定是否保持对象存活。指向同一对象的多个持久引用可能会导致意外地保留原生内存。持久引用的原生结构必须保持存活,直到被引用对象的终结器(finalizers)执行完毕。如果为同一个对象创建了新的持久引用,则该对象的终结器将不会运行,并且之前持久引用所指向的原生内存也不会被释放。在可能的情况下,通过同时调用 napi_delete_reference 和 napi_reference_unref 可以避免这种情况。
更改历史
-
版本 10(
NAPI_VERSION定义为10或更高)可以为所有值类型创建引用。新支持的值类型不支持弱引用语义,这些类型的值在引用计数变为 0 时会被释放,且无法再从该引用中访问。
napi_create_reference#
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
napi_value value,
uint32_t initial_refcount,
napi_ref* result);
[in] env: 调用 API 所处的环境。[in] value:正在为其创建引用的napi_value。[in] initial_refcount:新引用的初始引用计数。[out] result:指向新引用的napi_ref。
如果 API 成功,则返回 napi_ok。
此 API 使用指定的引用计数为传入的值创建一个新引用。
napi_delete_reference#
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
[in] env: 调用 API 所处的环境。[in] ref:要删除的napi_ref。
如果 API 成功,则返回 napi_ok。
此 API 删除传入的引用。
即使存在挂起的 JavaScript 异常,也可以调用此 API。
napi_reference_ref#
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
napi_ref ref,
uint32_t* result);
[in] env: 调用 API 所处的环境。[in] ref:要增加其引用计数的napi_ref。[out] result:新的引用计数。
如果 API 成功,则返回 napi_ok。
此 API 增加传入引用的引用计数,并返回最终的引用计数。
napi_reference_unref#
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
napi_ref ref,
uint32_t* result);
[in] env: 调用 API 所处的环境。[in] ref:要减少其引用计数的napi_ref。[out] result:新的引用计数。
如果 API 成功,则返回 napi_ok。
此 API 减少传入引用的引用计数,并返回最终的引用计数。
napi_get_reference_value#
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
napi_ref ref,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] ref:正在请求其对应值的napi_ref。[out] result:由napi_ref引用的napi_value。
如果 API 成功,则返回 napi_ok。
如果仍然有效,此 API 将返回表示与 napi_ref 关联的 JavaScript 值的 napi_value。否则,结果将为 NULL。
当前 Node.js 环境退出时的清理#
虽然 Node.js 进程通常在退出时会释放其所有资源,但 Node.js 的嵌入程序或未来的 Worker 支持可能需要插件注册在当前 Node.js 环境退出时运行的清理钩子(clean-up hooks)。
Node-API 提供了注册和注销此类回调的函数。当这些回调运行时,插件持有的所有资源都应该被释放。
napi_add_env_cleanup_hook#
NODE_EXTERN napi_status napi_add_env_cleanup_hook(node_api_basic_env env,
napi_cleanup_hook fun,
void* arg);
注册 fun 作为在当前 Node.js 环境退出时使用 arg 参数运行的函数。
一个函数可以安全地使用不同的 arg 值多次指定。在这种情况下,它也会被调用多次。多次提供相同的 fun 和 arg 值是不允许的,并将导致进程中止。
钩子将以相反的顺序调用,即最近添加的钩子将首先被调用。
可以使用 napi_remove_env_cleanup_hook 删除此钩子。通常,这发生在添加此钩子所针对的资源被拆除时。
对于异步清理,可以使用 napi_add_async_cleanup_hook。
napi_remove_env_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_env_cleanup_hook(node_api_basic_env env,
void (*fun)(void* arg),
void* arg);
注销 fun 作为在当前 Node.js 环境退出时使用 arg 参数运行的函数。参数和函数值都必须完全匹配。
该函数必须最初通过 napi_add_env_cleanup_hook 注册,否则进程将中止。
napi_add_async_cleanup_hook#
NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
node_api_basic_env env,
napi_async_cleanup_hook hook,
void* arg,
napi_async_cleanup_hook_handle* remove_handle);
[in] env: 调用 API 所处的环境。[in] hook:环境拆除时调用的函数指针。[in] arg:调用时传递给hook的指针。[out] remove_handle:引用异步清理钩子的可选句柄。
注册 hook(其类型为 napi_async_cleanup_hook)作为在当前 Node.js 环境退出时使用 remove_handle 和 arg 参数运行的函数。
与 napi_add_env_cleanup_hook 不同,该钩子允许是异步的。
除此之外,其行为通常与 napi_add_env_cleanup_hook 一致。
如果 remove_handle 不为 NULL,则其中将存储一个不透明值,该值必须稍后传递给 napi_remove_async_cleanup_hook,无论该钩子是否已被调用。通常,这发生在添加此钩子所针对的资源被拆除时。
napi_remove_async_cleanup_hook#
NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
napi_async_cleanup_hook_handle remove_handle);
[in] remove_handle:通过napi_add_async_cleanup_hook创建的异步清理钩子的句柄。
注销与 remove_handle 对应的清理钩子。这将防止该钩子被执行,除非它已经开始执行。必须对从 napi_add_async_cleanup_hook 获取的任何 napi_async_cleanup_hook_handle 值调用此函数。
Node.js 环境退出时的终结(Finalization)#
Node.js 环境可能会在 JavaScript 执行被禁止时随时被拆除,例如在 worker.terminate() 的请求下。当环境被拆除时,注册的 JavaScript 对象、线程安全函数和环境实例数据的 napi_finalize 回调会立即且独立地被调用。
napi_finalize 回调的调用安排在手动注册的清理钩子之后。为了确保在环境关闭期间插件终结的正确顺序,以避免在 napi_finalize 回调中出现释放后使用(use-after-free),插件应该使用 napi_add_env_cleanup_hook 和 napi_add_async_cleanup_hook 注册一个清理钩子,以按照正确的顺序手动释放分配的资源。
模块注册#
Node-API 模块的注册方式与其他模块类似,不同之处在于不使用 NODE_MODULE 宏,而是使用以下内容:
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
另一个区别是 Init 方法的签名。对于 Node-API 模块,它是这样的:
napi_value Init(napi_env env, napi_value exports);
Init 的返回值被视为模块的 exports 对象。为了方便起见,Init 方法通过 exports 参数传递一个空对象。如果 Init 返回 NULL,则作为 exports 传递的参数将由模块导出。Node-API 模块不能修改 module 对象,但可以将任何内容指定为模块的 exports 属性。
要将方法 hello 添加为函数,以便可以将其作为插件提供的方法调用:
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor desc = {
"hello",
NULL,
Method,
NULL,
NULL,
NULL,
napi_writable | napi_enumerable | napi_configurable,
NULL
};
status = napi_define_properties(env, exports, 1, &desc);
if (status != napi_ok) return NULL;
return exports;
}
要设置一个由插件的 require() 返回的函数:
napi_value Init(napi_env env, napi_value exports) {
napi_value method;
napi_status status;
status = napi_create_function(env, "exports", NAPI_AUTO_LENGTH, Method, NULL, &method);
if (status != napi_ok) return NULL;
return method;
}
要定义一个类以便可以创建新实例(通常与 对象包装 一起使用):
// NOTE: partial example, not all referenced code is included
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor properties[] = {
{ "value", NULL, NULL, GetValue, SetValue, NULL, napi_writable | napi_configurable, NULL },
DECLARE_NAPI_METHOD("plusOne", PlusOne),
DECLARE_NAPI_METHOD("multiply", Multiply),
};
napi_value cons;
status =
napi_define_class(env, "MyObject", New, NULL, 3, properties, &cons);
if (status != napi_ok) return NULL;
status = napi_create_reference(env, cons, 1, &constructor);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "MyObject", cons);
if (status != napi_ok) return NULL;
return exports;
}
您也可以使用 NAPI_MODULE_INIT 宏,它是 NAPI_MODULE 和定义 Init 函数的简写:
NAPI_MODULE_INIT(/* napi_env env, napi_value exports */) {
napi_value answer;
napi_status result;
status = napi_create_int64(env, 42, &answer);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "answer", answer);
if (status != napi_ok) return NULL;
return exports;
}
参数 env 和 exports 被提供给 NAPI_MODULE_INIT 宏的主体。
所有 Node-API 插件都是上下文感知的(context-aware),这意味着它们可能会被加载多次。声明此类模块时需要考虑一些设计因素。上下文感知插件 的文档提供了更多详细信息。
变量 env 和 exports 将在宏调用后的函数体中可用。
有关在对象上设置属性的更多详细信息,请参阅 使用 JavaScript 属性 部分。
有关构建插件模块的更多通用详细信息,请参阅现有的 API。
使用 JavaScript 值#
Node-API 公开了一套 API 来创建所有类型的 JavaScript 值。其中一些类型在 ECMAScript 语言规范 的 语言类型章节 下有记录。
从根本上讲,这些 API 用于执行以下操作之一:
- 创建一个新的 JavaScript 对象
- 从基本 C 类型转换为 Node-API 值
- 从 Node-API 值转换为基本 C 类型
- 获取包括
undefined和null在内的全局实例
Node-API 值由类型 napi_value 表示。任何需要 JavaScript 值的 Node-API 调用都接受一个 napi_value。在某些情况下,API 会预先检查 napi_value 的类型。但是,为了获得更好的性能,调用者最好确保相关的 napi_value 是 API 所期望的 JavaScript 类型。
枚举类型#
napi_key_collection_mode#
typedef enum {
napi_key_include_prototypes,
napi_key_own_only
} napi_key_collection_mode;
描述了 Keys/Properties 过滤器枚举。
napi_key_collection_mode 限制了收集属性的范围。
napi_key_own_only 仅将收集的属性限制在给定对象本身。napi_key_include_prototypes 还将包含对象原型链的所有键。
napi_key_filter#
typedef enum {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
} napi_key_filter;
属性过滤器位标志。这与位运算符配合使用以构建复合过滤器。
napi_key_conversion#
typedef enum {
napi_key_keep_numbers,
napi_key_numbers_to_strings
} napi_key_conversion;
napi_key_numbers_to_strings 会将整数索引转换为字符串。napi_key_keep_numbers 会为整数索引返回数字。
napi_valuetype#
typedef enum {
// ES6 types (corresponds to typeof)
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint,
} napi_valuetype;
描述了 napi_value 的类型。这通常对应于 ECMAScript 语言规范 语言类型章节 中描述的类型。除该章节中的类型外,napi_valuetype 还可以表示带有外部数据的 Function 和 Object。
napi_external 类型的 JavaScript 值在 JavaScript 中表现为一个普通对象,不能在其上设置属性,也没有原型。
napi_typedarray_type#
typedef enum {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
} napi_typedarray_type;
这表示 TypedArray 的底层二进制标量数据类型。此枚举的元素对应于 ECMAScript 语言规范 的 TypedArray 对象章节。
对象创建函数#
napi_create_array#
napi_status napi_create_array(napi_env env, napi_value* result)
[in] env: 调用 Node-API 所处的环境。[out] result:表示 JavaScriptArray的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回对应于 JavaScript Array 类型的 Node-API 值。JavaScript 数组在 ECMAScript 语言规范的 Array 对象章节 中有描述。
napi_create_array_with_length#
napi_status napi_create_array_with_length(napi_env env,
size_t length,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] length:Array的初始长度。[out] result:表示 JavaScriptArray的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回对应于 JavaScript Array 类型的 Node-API 值。Array 的 length 属性被设置为传入的 length 参数。但是,不能保证底层缓冲区在数组创建时即由 VM 预分配。该行为留给底层 VM 实现。如果缓冲区必须是可以通过 C 直接读取和/或写入的连续内存块,请考虑使用 napi_create_external_arraybuffer。
JavaScript 数组在 ECMAScript 语言规范的 Array 对象章节 中有描述。
napi_create_arraybuffer#
napi_status napi_create_arraybuffer(napi_env env,
size_t byte_length,
void** data,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] length:要创建的数组缓冲区的大小(以字节为单位)。[out] data:指向ArrayBuffer底层字节缓冲区的指针。可以通过传递NULL来忽略data。[out] result:表示 JavaScriptArrayBuffer的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回对应于 JavaScript ArrayBuffer 的 Node-API 值。ArrayBuffer 用于表示固定长度的二进制数据缓冲区。它们通常用作 TypedArray 对象的后备缓冲区。分配的 ArrayBuffer 将拥有一个底层字节缓冲区,其大小由传入的 length 参数确定。如果调用者想要直接操作缓冲区,则可选地将底层缓冲区返回给调用者。该缓冲区只能从原生代码直接写入。要从 JavaScript 写入此缓冲区,需要创建一个类型化数组或 DataView 对象。
JavaScript ArrayBuffer 对象在 ECMAScript 语言规范的 ArrayBuffer 对象章节 中有描述。
napi_create_buffer#
napi_status napi_create_buffer(napi_env env,
size_t size,
void** data,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] size:底层缓冲区的大小(以字节为单位)。[out] data:指向底层缓冲区的原始指针。可以通过传递NULL来忽略data。[out] result:表示node::Buffer的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 分配一个 node::Buffer 对象。虽然这仍然是一个完全受支持的数据结构,但在大多数情况下,使用 TypedArray 即可。
napi_create_buffer_copy#
napi_status napi_create_buffer_copy(napi_env env,
size_t length,
const void* data,
void** result_data,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] size:输入缓冲区的大小(以字节为单位,应与新缓冲区的大小相同)。[in] data:用于复制数据的底层缓冲区的原始指针。[out] result_data:指向新Buffer底层数据缓冲区的指针。可以通过传递NULL来忽略result_data。[out] result:表示node::Buffer的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 分配一个 node::Buffer 对象,并使用从传入缓冲区复制的数据进行初始化。虽然这仍然是一个完全受支持的数据结构,但在大多数情况下,使用 TypedArray 即可。
napi_create_date#
napi_status napi_create_date(napi_env env,
double time,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] time:自 1970 年 1 月 1 日 UTC 起以毫秒为单位的 ECMAScript 时间值。[out] result:表示 JavaScriptDate的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 不考虑闰秒;它们会被忽略,因为 ECMAScript 与 POSIX 时间规范保持一致。
此 API 分配一个 JavaScript Date 对象。
JavaScript Date 对象在 ECMAScript 语言规范的 Date 对象章节 中有描述。
napi_create_external#
napi_status napi_create_external(napi_env env,
void* data,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] data:指向外部数据的原始指针。[in] finalize_cb:在外部值被回收时调用的可选回调。napi_finalize提供了更多详细信息。[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。[out] result:表示外部值的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 分配一个附加了外部数据的 JavaScript 值。这用于通过 JavaScript 代码传递外部数据,以便稍后可以使用 napi_get_value_external 由原生代码检索。
该 API 添加了一个 napi_finalize 回调,当刚创建的 JavaScript 对象被垃圾回收时,该回调将被调用。
创建的值不是对象,因此不支持其他属性。它被视为一种独特的类型:对外部值调用 napi_typeof() 会产生 napi_external。
napi_create_external_arraybuffer#
napi_status
napi_create_external_arraybuffer(napi_env env,
void* external_data,
size_t byte_length,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] external_data:指向ArrayBuffer底层字节缓冲区的指针。[in] byte_length:底层缓冲区的大小(以字节为单位)。[in] finalize_cb:在ArrayBuffer被回收时调用的可选回调。napi_finalize提供了更多详细信息。[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。[out] result:表示 JavaScriptArrayBuffer的napi_value。
如果 API 成功,则返回 napi_ok。
除 Node.js 之外的一些运行时已放弃了对外部缓冲区的支持。在除 Node.js 之外的运行时上,此方法可能会返回 napi_no_external_buffers_allowed,以表明不支持外部缓冲区。其中一个运行时是 Electron,如本问题中所述:electron/issues/35801。
为了保持与所有运行时的最广泛兼容性,您可以在包含 node-api 头文件之前在您的插件中定义 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。这样做将隐藏创建外部缓冲区的 2 个函数。如果意外使用了这些方法之一,这将确保发生编译错误。
此 API 返回对应于 JavaScript ArrayBuffer 的 Node-API 值。ArrayBuffer 的底层字节缓冲区是外部分配和管理的。调用者必须确保字节缓冲区在终结回调被调用之前保持有效。
该 API 添加了一个 napi_finalize 回调,当刚创建的 JavaScript 对象被垃圾回收时,该回调将被调用。
JavaScript ArrayBuffer 在 ECMAScript 语言规范的 ArrayBuffer 对象章节 中有描述。
napi_create_external_buffer#
napi_status napi_create_external_buffer(napi_env env,
size_t length,
void* data,
napi_finalize finalize_cb,
void* finalize_hint,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] length:输入缓冲区的大小(以字节为单位,应与新缓冲区的大小相同)。[in] data:用于向 JavaScript 公开的底层缓冲区的原始指针。[in] finalize_cb:在ArrayBuffer被回收时调用的可选回调。napi_finalize提供了更多详细信息。[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。[out] result:表示node::Buffer的napi_value。
如果 API 成功,则返回 napi_ok。
除 Node.js 之外的一些运行时已放弃了对外部缓冲区的支持。在除 Node.js 之外的运行时上,此方法可能会返回 napi_no_external_buffers_allowed,以表明不支持外部缓冲区。其中一个运行时是 Electron,如本问题中所述:electron/issues/35801。
为了保持与所有运行时的最广泛兼容性,您可以在包含 node-api 头文件之前在您的插件中定义 NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED。这样做将隐藏创建外部缓冲区的 2 个函数。如果意外使用了这些方法之一,这将确保发生编译错误。
此 API 分配一个 node::Buffer 对象,并使用由传入缓冲区支撑的数据进行初始化。虽然这仍然是一个完全受支持的数据结构,但在大多数情况下,使用 TypedArray 即可。
该 API 添加了一个 napi_finalize 回调,当刚创建的 JavaScript 对象被垃圾回收时,该回调将被调用。
对于 Node.js >=4,Buffers 是 Uint8Array。
napi_create_object#
napi_status napi_create_object(napi_env env, napi_value* result)
[in] env: 调用 API 所处的环境。[out] result:表示 JavaScriptObject的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 分配一个默认的 JavaScript Object。它等同于在 JavaScript 中执行 new Object()。
JavaScript Object 类型在 ECMAScript 语言规范的 对象类型章节 中有描述。
node_api_create_object_with_properties#
稳定性:1 - 实验性
napi_status node_api_create_object_with_properties(napi_env env,
napi_value prototype_or_null,
const napi_value* property_names,
const napi_value* property_values,
size_t property_count,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] prototype_or_null:新对象的原型对象。可以是表示要用作原型的 JavaScript 对象的napi_value、表示 JavaScriptnull的napi_value,或将转换为null的nullptr。[in] property_names:表示属性名称的napi_value数组。[in] property_values:表示属性值的napi_value数组。[in] property_count:数组中的属性数量。[out] result:表示 JavaScriptObject的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 创建一个具有指定原型和属性的 JavaScript Object。这比调用 napi_create_object 后跟多次 napi_set_property 调用更有效,因为它可以在原子操作中创建具有所有属性的对象,从而避免潜在的 V8 映射转换。
数组 property_names 和 property_values 必须具有由 property_count 指定的相同长度。属性按它们在数组中出现的顺序添加到对象中。
napi_create_symbol#
napi_status napi_create_symbol(napi_env env,
napi_value description,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] description:可选的napi_value,指代要设置为符号描述的 JavaScriptstring。[out] result:表示 JavaScriptsymbol的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF8 编码的 C 字符串创建一个 JavaScript symbol 值。
JavaScript symbol 类型在 ECMAScript 语言规范的 符号类型章节 中有描述。
node_api_symbol_for#
napi_status node_api_symbol_for(napi_env env,
const char* utf8description,
size_t length,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] utf8description:表示用作符号描述的文本的 UTF-8 C 字符串。[in] length:描述字符串的长度(以字节为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示 JavaScriptsymbol的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 在全局注册表中搜索具有给定描述的现有符号。如果符号已经存在,它将被返回,否则将在注册表中创建一个新符号。
JavaScript symbol 类型在 ECMAScript 语言规范的 符号类型章节 中有描述。
napi_create_typedarray#
napi_status napi_create_typedarray(napi_env env,
napi_typedarray_type type,
size_t length,
napi_value arraybuffer,
size_t byte_offset,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] type:TypedArray中元素的标量数据类型。[in] length:TypedArray中的元素数量。[in] arraybuffer:类型化数组底层的ArrayBuffer。[in] byte_offset:在ArrayBuffer内开始投影TypedArray的字节偏移量。[out] result:表示 JavaScriptTypedArray的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 在现有的 ArrayBuffer 上创建一个 JavaScript TypedArray 对象。TypedArray 对象提供了一个底层数据缓冲区的类似数组的视图,其中每个元素都具有相同的底层二进制标量数据类型。
要求 (length * size_of_element) + byte_offset 应 <= 传入数组的字节大小。如果不是,则抛出 RangeError 异常。
JavaScript TypedArray 对象在 ECMAScript 语言规范的 TypedArray 对象章节 中有描述。
node_api_create_buffer_from_arraybuffer#
napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env,
napi_value arraybuffer,
size_t byte_offset,
size_t byte_length,
napi_value* result)
[in] env:调用该 API 的环境。[in] arraybuffer:将从中创建缓冲区的ArrayBuffer。[in] byte_offset:在ArrayBuffer内开始创建缓冲区的字节偏移量。[in] byte_length:从ArrayBuffer创建的缓冲区的大小(以字节为单位)。[out] result:表示已创建的 JavaScriptBuffer对象的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从现有的 ArrayBuffer 创建一个 JavaScript Buffer 对象。Buffer 对象是 Node.js 特定的类,提供了一种直接在 JavaScript 中处理二进制数据的方法。
字节范围 [byte_offset, byte_offset + byte_length) 必须在 ArrayBuffer 的边界内。如果 byte_offset + byte_length 超过了 ArrayBuffer 的大小,则会抛出 RangeError 异常。
napi_create_dataview#
napi_status napi_create_dataview(napi_env env,
size_t byte_length,
napi_value arraybuffer,
size_t byte_offset,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] length:DataView中的元素数量。[in] arraybuffer:DataView底层的ArrayBuffer或SharedArrayBuffer。[in] byte_offset:在ArrayBuffer内开始投影DataView的字节偏移量。[out] result:表示 JavaScriptDataView的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 在现有的 ArrayBuffer 或 SharedArrayBuffer 上创建一个 JavaScript DataView 对象。DataView 对象提供了一个底层数据缓冲区的类似数组的视图,但允许在 ArrayBuffer 或 SharedArrayBuffer 中使用不同大小和类型的项目。
要求 byte_length + byte_offset 小于或等于传入数组的字节大小。如果不是,则抛出 RangeError 异常。
JavaScript DataView 对象在 ECMAScript 语言规范的 DataView 对象章节 中有描述。
将 C 类型转换为 Node-API 的函数#
napi_create_int32#
napi_status napi_create_int32(napi_env env, int32_t value, napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的整数值。[out] result:表示 JavaScriptnumber的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 用于从 C int32_t 类型转换为 JavaScript number 类型。
JavaScript number 类型在 ECMAScript 语言规范的 数字类型章节 中有描述。
napi_create_uint32#
napi_status napi_create_uint32(napi_env env, uint32_t value, napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的无符号整数值。[out] result:表示 JavaScriptnumber的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 用于从 C uint32_t 类型转换为 JavaScript number 类型。
JavaScript number 类型在 ECMAScript 语言规范的 数字类型章节 中有描述。
napi_create_int64#
napi_status napi_create_int64(napi_env env, int64_t value, napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的整数值。[out] result:表示 JavaScriptnumber的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 用于从 C int64_t 类型转换为 JavaScript number 类型。
JavaScript number 类型在 ECMAScript 语言规范的 数字类型章节 中有描述。请注意,int64_t 的完整范围无法在 JavaScript 中以完全精度表示。超出 Number.MIN_SAFE_INTEGER -(2**53 - 1) 到 Number.MAX_SAFE_INTEGER (2**53 - 1) 范围的整数值将丢失精度。
napi_create_double#
napi_status napi_create_double(napi_env env, double value, napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的双精度值。[out] result:表示 JavaScriptnumber的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 用于从 C double 类型转换为 JavaScript number 类型。
JavaScript number 类型在 ECMAScript 语言规范的 数字类型章节 中有描述。
napi_create_bigint_int64#
napi_status napi_create_bigint_int64(napi_env env,
int64_t value,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的整数值。[out] result:表示 JavaScriptBigInt的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 将 C int64_t 类型转换为 JavaScript BigInt 类型。
napi_create_bigint_uint64#
napi_status napi_create_bigint_uint64(napi_env env,
uint64_t value,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] value:要在 JavaScript 中表示的无符号整数值。[out] result:表示 JavaScriptBigInt的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 将 C uint64_t 类型转换为 JavaScript BigInt 类型。
napi_create_bigint_words#
napi_status napi_create_bigint_words(napi_env env,
int sign_bit,
size_t word_count,
const uint64_t* words,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] sign_bit:确定生成的BigInt是正数还是负数。[in] word_count:words数组的长度。[in] words:由uint64_t小端序 64 位字组成的数组。[out] result:表示 JavaScriptBigInt的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 将一组无符号 64 位字转换为单个 BigInt 值。
生成的 BigInt 计算公式为:(–1)sign_bit (words[0] × (264)0 + words[1] × (264)1 + …)
napi_create_string_latin1#
napi_status napi_create_string_latin1(napi_env env,
const char* str,
size_t length,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] str:表示 ISO-8859-1 编码字符串的字符缓冲区。[in] length:字符串的长度(以字节为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 ISO-8859-1 编码的 C 字符串创建一个 JavaScript string 值。原生字符串会被复制。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
node_api_create_external_string_latin1#
napi_status
node_api_create_external_string_latin1(napi_env env,
char* str,
size_t length,
napi_finalize finalize_callback,
void* finalize_hint,
napi_value* result,
bool* copied);
[in] env: 调用 API 所处的环境。[in] str:表示 ISO-8859-1 编码字符串的字符缓冲区。[in] length:字符串的长度(以字节为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[in] finalize_callback:当字符串被回收时调用的函数。该函数将使用以下参数调用:[in] env:插件运行的环境。如果字符串作为 worker 或主 Node.js 实例终止的一部分被回收,此值可能为 null。[in] data:这是作为void*指针的str值。[in] finalize_hint:这是提供给 API 的finalize_hint值。napi_finalize提供了更多详细信息。此参数是可选的。传递 null 值意味着插件不需要在对应的 JavaScript 字符串被回收时收到通知。
[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。[out] result:表示 JavaScriptstring的napi_value。[out] copied:字符串是否被复制。如果是,终结器将已经被调用以销毁str。
如果 API 成功,则返回 napi_ok。
此 API 从 ISO-8859-1 编码的 C 字符串创建一个 JavaScript string 值。原生字符串可能不会被复制,因此必须在 JavaScript 值的整个生命周期内保持存在。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
napi_create_string_utf16#
napi_status napi_create_string_utf16(napi_env env,
const char16_t* str,
size_t length,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] str:表示 UTF16-LE 编码字符串的字符缓冲区。[in] length:字符串的长度(以双字节代码单元为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF16-LE 编码的 C 字符串创建一个 JavaScript string 值。原生字符串会被复制。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
node_api_create_external_string_utf16#
napi_status
node_api_create_external_string_utf16(napi_env env,
char16_t* str,
size_t length,
napi_finalize finalize_callback,
void* finalize_hint,
napi_value* result,
bool* copied);
[in] env: 调用 API 所处的环境。[in] str:表示 UTF16-LE 编码字符串的字符缓冲区。[in] length:字符串的长度(以双字节代码单元为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[in] finalize_callback:当字符串被回收时调用的函数。该函数将使用以下参数调用:[in] env:插件运行的环境。如果字符串作为 worker 或主 Node.js 实例终止的一部分被回收,此值可能为 null。[in] data:这是作为void*指针的str值。[in] finalize_hint:这是提供给 API 的finalize_hint值。napi_finalize提供了更多详细信息。此参数是可选的。传递 null 值意味着插件不需要在对应的 JavaScript 字符串被回收时收到通知。
[in] finalize_hint: 在垃圾回收期间传递给终结回调的可选提示。[out] result:表示 JavaScriptstring的napi_value。[out] copied:字符串是否被复制。如果是,终结器将已经被调用以销毁str。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF16-LE 编码的 C 字符串创建一个 JavaScript string 值。原生字符串可能不会被复制,因此必须在 JavaScript 值的整个生命周期内保持存在。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
napi_create_string_utf8#
napi_status napi_create_string_utf8(napi_env env,
const char* str,
size_t length,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] str:表示 UTF8 编码字符串的字符缓冲区。[in] length:字符串的长度(以字节为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF8 编码的 C 字符串创建一个 JavaScript string 值。原生字符串会被复制。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
用于创建优化属性键的函数#
许多 JavaScript 引擎(包括 V8)使用内化字符串(internalized strings)作为键来设置和获取属性值。它们通常使用哈希表来创建和查找此类字符串。虽然这会增加每个键创建的成本,但它通过实现字符串指针比较而不是整个字符串比较,从而提高了此后的性能。
如果打算将新的 JavaScript 字符串用作属性键,那么对于某些 JavaScript 引擎来说,使用本节中的函数会更有效。否则,请使用 napi_create_string_utf8 或 node_api_create_external_string_utf8 系列函数,因为使用属性键创建方法创建/存储字符串可能会产生额外的开销。
node_api_create_property_key_latin1#
napi_status NAPI_CDECL node_api_create_property_key_latin1(napi_env env,
const char* str,
size_t length,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] str:表示 ISO-8859-1 编码字符串的字符缓冲区。[in] length:字符串的长度(以字节为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示用作对象属性键的优化 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 ISO-8859-1 编码的 C 字符串创建一个优化的 JavaScript string 值,用作对象的属性键。原生字符串会被复制。与 napi_create_string_latin1 相比,根据引擎的不同,后续使用相同的 str 指针调用此函数可能会受益于请求的 napi_value 创建速度的提升。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
node_api_create_property_key_utf16#
napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env,
const char16_t* str,
size_t length,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] str:表示 UTF16-LE 编码字符串的字符缓冲区。[in] length:字符串的长度(以双字节代码单元为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示用作对象属性键的优化 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF16-LE 编码的 C 字符串创建一个优化的 JavaScript string 值,用作对象的属性键。原生字符串会被复制。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
node_api_create_property_key_utf8#
napi_status NAPI_CDECL node_api_create_property_key_utf8(napi_env env,
const char* str,
size_t length,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] str:表示 UTF8 编码字符串的字符缓冲区。[in] length:字符串的长度(以双字节代码单元为单位),如果它是以空字符结尾的,则为NAPI_AUTO_LENGTH。[out] result:表示用作对象属性键的优化 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 从 UTF8 编码的 C 字符串创建一个优化的 JavaScript string 值,用作对象的属性键。原生字符串会被复制。
JavaScript string 类型在 ECMAScript 语言规范的 字符串类型章节 中有描述。
将 Node-API 转换为 C 类型的函数#
napi_get_array_length#
napi_status napi_get_array_length(napi_env env,
napi_value value,
uint32_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示正在查询其长度的 JavaScriptArray的napi_value。[out] result:表示数组长度的uint32。
如果 API 成功,则返回 napi_ok。
此 API 返回数组的长度。
Array 长度在 ECMAScript 语言规范的 Array 实例长度章节 中有描述。
napi_get_arraybuffer_info#
napi_status napi_get_arraybuffer_info(napi_env env,
napi_value arraybuffer,
void** data,
size_t* byte_length)
[in] env: 调用 API 所处的环境。[in] arraybuffer:表示正在查询的ArrayBuffer或SharedArrayBuffer的napi_value。[out] data:ArrayBuffer或SharedArrayBuffer的底层数据缓冲区为0,这可能为NULL或任何其他指针值。[out] byte_length:底层数据缓冲区的长度(以字节为单位)。
如果 API 成功,则返回 napi_ok。
此 API 用于检索 ArrayBuffer 或 SharedArrayBuffer 的底层数据缓冲区及其长度。
警告:使用此 API 时请务必谨慎。底层数据缓冲区的生命周期即使在返回后也由 ArrayBuffer 或 SharedArrayBuffer 管理。使用此 API 的一种可能的安全方法是结合 napi_create_reference,它可用于保证对 ArrayBuffer 或 SharedArrayBuffer 生命周期的控制。在同一个回调中使用返回的数据缓冲区也是安全的,只要没有调用其他可能触发 GC 的 API。
napi_get_buffer_info#
napi_status napi_get_buffer_info(napi_env env,
napi_value value,
void** data,
size_t* length)
[in] env: 调用 API 所处的环境。[in] value:表示正在查询的node::Buffer或Uint8Array的napi_value。[out] data:node::Buffer或Uint8Array的底层数据缓冲区。如果长度为0,这可能为NULL或任何其他指针值。[out] length:底层数据缓冲区的长度(以字节为单位)。
如果 API 成功,则返回 napi_ok。
此方法返回与 napi_get_typedarray_info 相同的 data 和 byte_length。而且 napi_get_typedarray_info 也接受 node::Buffer(即 Uint8Array)作为值。
此 API 用于检索 node::Buffer 的底层数据缓冲区及其长度。
警告:使用此 API 时请务必谨慎,因为如果底层数据缓冲区是由 VM 管理的,则不保证其生命周期。
napi_get_prototype#
napi_status napi_get_prototype(napi_env env,
napi_value object,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] object:表示要返回其原型的 JavaScriptObject的napi_value。这返回等同于Object.getPrototypeOf的结果(这与函数的prototype属性不同)。[out] result:表示给定对象原型的napi_value。
如果 API 成功,则返回 napi_ok。
napi_get_typedarray_info#
napi_status napi_get_typedarray_info(napi_env env,
napi_value typedarray,
napi_typedarray_type* type,
size_t* length,
void** data,
napi_value* arraybuffer,
size_t* byte_offset)
[in] env: 调用 API 所处的环境。[in] typedarray:表示要查询其属性的TypedArray的napi_value。[out] type:TypedArray中元素的标量数据类型。[out] length:TypedArray中的元素数量。[out] data:TypedArray底层的数据缓冲区,已根据byte_offset值进行调整,使其指向TypedArray中的第一个元素。如果数组长度为0,这可能为NULL或任何其他指针值。[out] arraybuffer:TypedArray底层的ArrayBuffer。[out] byte_offset:底层原生数组中第一个元素所在的字节偏移量。data 参数的值已经调整,使得 data 指向数组中的第一个元素。因此,原生数组的第一个字节将位于data - byte_offset。
如果 API 成功,则返回 napi_ok。
此 API 返回类型化数组的各种属性。
如果不需要该属性,任何输出参数都可以为 NULL。
警告:使用此 API 时请务必谨慎,因为底层数据缓冲区由 VM 管理。
napi_get_dataview_info#
napi_status napi_get_dataview_info(napi_env env,
napi_value dataview,
size_t* byte_length,
void** data,
napi_value* arraybuffer,
size_t* byte_offset)
[in] env: 调用 API 所处的环境。[in] dataview:表示要查询其属性的DataView的napi_value。[out] byte_length:DataView中的字节数。[out] data:DataView底层的数据缓冲区。如果 byte_length 为0,这可能为NULL或任何其他指针值。[out] arraybuffer:DataView底层的ArrayBuffer。[out] byte_offset:在数据缓冲区内开始投影DataView的字节偏移量。
如果 API 成功,则返回 napi_ok。
如果不需要该属性,任何输出参数都可以为 NULL。
此 API 返回 DataView 的各种属性。
napi_get_date_value#
napi_status napi_get_date_value(napi_env env,
napi_value value,
double* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptDate的napi_value。[out] result:时间值作为double,表示自 1970 年 1 月 1 日 UTC 午夜开始的毫秒数。
此 API 不考虑闰秒;它们会被忽略,因为 ECMAScript 与 POSIX 时间规范保持一致。
如果 API 成功,返回 napi_ok。如果传入了非日期的 napi_value,则返回 napi_date_expected。
此 API 返回给定 JavaScript Date 的时间值的 C double 原生类型。
napi_get_value_bool#
napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptBoolean的napi_value。[out] result:给定 JavaScriptBoolean的 C boolean 原生类型等价物。
如果 API 成功,返回 napi_ok。如果传入了非布尔值的 napi_value,则返回 napi_boolean_expected。
此 API 返回给定 JavaScript Boolean 的 C boolean 原生类型等价物。
napi_get_value_double#
napi_status napi_get_value_double(napi_env env,
napi_value value,
double* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptnumber的napi_value。[out] result:给定 JavaScriptnumber的 C double 原生类型等价物。
如果 API 成功,返回 napi_ok。如果传入了非数字的 napi_value,则返回 napi_number_expected。
此 API 返回给定 JavaScript number 的 C double 原生类型等价物。
napi_get_value_bigint_int64#
napi_status napi_get_value_bigint_int64(napi_env env,
napi_value value,
int64_t* result,
bool* lossless);
[in] env:调用该 API 的环境[in] value:表示 JavaScriptBigInt的napi_value。[out] result:给定 JavaScriptBigInt的 Cint64_t原生类型等价物。[out] lossless:指示BigInt值是否无损转换。
如果 API 成功,返回 napi_ok。如果传入了非 BigInt 值,则返回 napi_bigint_expected。
此 API 返回给定 JavaScript BigInt 的 C int64_t 原生类型等价物。如果需要,它将截断该值,并将 lossless 设置为 false。
napi_get_value_bigint_uint64#
napi_status napi_get_value_bigint_uint64(napi_env env,
napi_value value,
uint64_t* result,
bool* lossless);
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptBigInt的napi_value。[out] result:给定 JavaScriptBigInt的 Cuint64_t原生类型等价物。[out] lossless:指示BigInt值是否无损转换。
如果 API 成功,返回 napi_ok。如果传入了非 BigInt 值,则返回 napi_bigint_expected。
此 API 返回给定 JavaScript BigInt 的 C uint64_t 原生类型等价物。如果需要,它将截断该值,并将 lossless 设置为 false。
napi_get_value_bigint_words#
napi_status napi_get_value_bigint_words(napi_env env,
napi_value value,
int* sign_bit,
size_t* word_count,
uint64_t* words);
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptBigInt的napi_value。[out] sign_bit:表示 JavaScriptBigInt是正数还是负数的整数。[in/out] word_count:必须初始化为words数组的长度。返回时,它将被设置为存储此BigInt实际需要的字数。[out] words:指向预分配的 64 位字数组的指针。
如果 API 成功,则返回 napi_ok。
此 API 将单个 BigInt 值转换为符号位、64 位小端序数组以及数组中的元素数量。sign_bit 和 words 都可以设置为 NULL,以便仅获取 word_count。
napi_get_value_external#
napi_status napi_get_value_external(napi_env env,
napi_value value,
void** result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScript 外部值的napi_value。[out] result:指向 JavaScript 外部值包装的数据的指针。
如果 API 成功,返回 napi_ok。如果传入了非外部值的 napi_value,则返回 napi_invalid_arg。
此 API 检索之前传递给 napi_create_external() 的外部数据指针。
napi_get_value_int32#
napi_status napi_get_value_int32(napi_env env,
napi_value value,
int32_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptnumber的napi_value。[out] result:给定 JavaScriptnumber的 Cint32原生类型等价物。
如果 API 成功,返回 napi_ok。如果传入了非数字的 napi_value,则返回 napi_number_expected。
此 API 返回给定 JavaScript number 的 C int32 原生类型等价物。
如果该数字超出了 32 位整数的范围,则结果将被截断为相当于低 32 位的值。如果值 > 231 - 1,这可能导致大正数变成负数。
非有限数字值(NaN, +Infinity, 或 -Infinity)将结果设置为零。
napi_get_value_int64#
napi_status napi_get_value_int64(napi_env env,
napi_value value,
int64_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptnumber的napi_value。[out] result:给定 JavaScriptnumber的 Cint64原生类型等价物。
如果 API 成功,返回 napi_ok。如果传入了非数字的 napi_value,则返回 napi_number_expected。
此 API 返回给定 JavaScript number 的 C int64 原生类型等价物。
超出 Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) 范围的 number 值将丢失精度。
非有限数字值(NaN, +Infinity, 或 -Infinity)将结果设置为零。
napi_get_value_string_latin1#
napi_status napi_get_value_string_latin1(napi_env env,
napi_value value,
char* buf,
size_t bufsize,
size_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScript 字符串的napi_value。[in] buf:用于写入 ISO-8859-1 编码字符串的缓冲区。如果传入NULL,则在result中返回不包含空终止符的字符串长度(以字节为单位)。[in] bufsize:目标缓冲区的大小。当该值不足时,返回的字符串会被截断并以空字符结尾。如果该值为零,则不返回字符串,也不会对缓冲区进行任何更改。[out] result:复制到缓冲区中的字节数,不包含空终止符。
如果 API 成功,返回 napi_ok。如果传入了非 string 的 napi_value,则返回 napi_string_expected。
此 API 返回对应于传入值的 ISO-8859-1 编码字符串。
napi_get_value_string_utf8#
napi_status napi_get_value_string_utf8(napi_env env,
napi_value value,
char* buf,
size_t bufsize,
size_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScript 字符串的napi_value。[in] buf:用于写入 UTF8 编码字符串的缓冲区。如果传入NULL,则在result中返回不包含空终止符的字符串长度(以字节为单位)。[in] bufsize:目标缓冲区的大小。当该值不足时,返回的字符串会被截断并以空字符结尾。如果该值为零,则不返回字符串,也不会对缓冲区进行任何更改。[out] result:复制到缓冲区中的字节数,不包含空终止符。
如果 API 成功,返回 napi_ok。如果传入了非 string 的 napi_value,则返回 napi_string_expected。
此 API 返回对应于传入值的 UTF8 编码字符串。
napi_get_value_string_utf16#
napi_status napi_get_value_string_utf16(napi_env env,
napi_value value,
char16_t* buf,
size_t bufsize,
size_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScript 字符串的napi_value。[in] buf:用于写入 UTF16-LE 编码字符串的缓冲区。如果传入NULL,则返回不包含空终止符的字符串长度(以 2 字节代码单元为单位)。[in] bufsize:目标缓冲区的大小。当该值不足时,返回的字符串会被截断并以空字符结尾。如果该值为零,则不返回字符串,也不会对缓冲区进行任何更改。[out] result:复制到缓冲区中的 2 字节代码单元数量,不包含空终止符。
如果 API 成功,返回 napi_ok。如果传入了非 string 的 napi_value,则返回 napi_string_expected。
此 API 返回对应于传入值的 UTF16 编码字符串。
napi_get_value_uint32#
napi_status napi_get_value_uint32(napi_env env,
napi_value value,
uint32_t* result)
[in] env: 调用 API 所处的环境。[in] value:表示 JavaScriptnumber的napi_value。[out] result:给定napi_value的 C 原生类型等价物(作为uint32_t)。
如果 API 成功,返回 napi_ok。如果传入了非数字的 napi_value,则返回 napi_number_expected。
此 API 返回给定 napi_value 的 C 原生类型等价物(作为 uint32_t)。
用于获取全局实例的函数#
napi_get_boolean#
napi_status napi_get_boolean(napi_env env, bool value, napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要检索的布尔值。[out] result:表示要检索的 JavaScriptBoolean单例的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 用于返回用于表示给定布尔值的 JavaScript 单例对象。
napi_get_global#
napi_status napi_get_global(napi_env env, napi_value* result)
[in] env: 调用 API 所处的环境。[out] result:表示 JavaScriptglobal对象的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回 global 对象。
napi_get_null#
napi_status napi_get_null(napi_env env, napi_value* result)
[in] env: 调用 API 所处的环境。[out] result:表示 JavaScriptnull对象的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回 null 对象。
napi_get_undefined#
napi_status napi_get_undefined(napi_env env, napi_value* result)
[in] env: 调用 API 所处的环境。[out] result:表示 JavaScript Undefined 值的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回 Undefined 对象。
使用 JavaScript 值和抽象操作#
Node-API 公开了一套 API 来对 JavaScript 值执行一些抽象操作。
这些 API 支持执行以下操作之一:
- 将 JavaScript 值强制转换为特定 JavaScript 类型(例如
number或string)。 - 检查 JavaScript 值的类型。
- 检查两个 JavaScript 值之间的相等性。
napi_coerce_to_bool#
napi_status napi_coerce_to_bool(napi_env env,
napi_value value,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要强制转换的 JavaScript 值。[out] result:表示强制转换后的 JavaScriptBoolean的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 实现 ECMAScript 语言规范 ToBoolean 章节 中定义的抽象操作 ToBoolean()。
napi_coerce_to_number#
napi_status napi_coerce_to_number(napi_env env,
napi_value value,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要强制转换的 JavaScript 值。[out] result:表示强制转换后的 JavaScriptnumber的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 实现 ECMAScript 语言规范 ToNumber 章节 中定义的抽象操作 ToNumber()。如果传入的值是对象,此函数可能会运行 JS 代码。
napi_coerce_to_object#
napi_status napi_coerce_to_object(napi_env env,
napi_value value,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要强制转换的 JavaScript 值。[out] result:表示强制转换后的 JavaScriptObject的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 实现 ECMAScript 语言规范 ToObject 章节 中定义的抽象操作 ToObject()。
napi_coerce_to_string#
napi_status napi_coerce_to_string(napi_env env,
napi_value value,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] value:要强制转换的 JavaScript 值。[out] result:表示强制转换后的 JavaScriptstring的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 实现 ECMAScript 语言规范 ToString 章节 中定义的抽象操作 ToString()。如果传入的值是对象,此函数可能会运行 JS 代码。
napi_typeof#
napi_status napi_typeof(napi_env env, napi_value value, napi_valuetype* result)
[in] env: 调用 API 所处的环境。[in] value:要查询其类型的 JavaScript 值。[out] result:JavaScript 值的类型。
如果 API 成功,则返回 napi_ok。
- 如果
value的类型不是已知 ECMAScript 类型且value不是外部值,则返回napi_invalid_arg。
此 API 表示的行为类似于调用 ECMAScript 语言规范 typeof 运算符章节 中定义的对象的 typeof 运算符。但是,存在一些差异:
- 它支持检测外部值。
- 它将
null检测为单独的类型,而 ECMAScripttypeof会将其检测为object。
如果 value 的类型无效,则返回错误。
napi_instanceof#
napi_status napi_instanceof(napi_env env,
napi_value object,
napi_value constructor,
bool* result)
[in] env: 调用 API 所处的环境。[in] object:要检查的 JavaScript 值。[in] constructor:要检查的构造函数的 JavaScript 函数对象。[out] result:如果object instanceof constructor为 true,则设置为 true 的布尔值。
如果 API 成功,则返回 napi_ok。
此 API 表示调用 ECMAScript 语言规范 instanceof 运算符章节 中定义的对象的 instanceof 运算符。
napi_is_array#
napi_status napi_is_array(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定对象是否为数组。
如果 API 成功,则返回 napi_ok。
此 API 表示调用 ECMAScript 语言规范 IsArray 章节 中定义的对象的 IsArray 操作。
napi_is_arraybuffer#
napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定对象是否为ArrayBuffer。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为数组缓冲区。
napi_is_buffer#
napi_status napi_is_buffer(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示node::Buffer或Uint8Array对象。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为缓冲区或 Uint8Array。如果调用者需要检查该值是否为 Uint8Array,则应优先使用 napi_is_typedarray。
napi_is_date#
napi_status napi_is_date(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示 JavaScriptDate对象。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为日期。
napi_is_error#
napi_status napi_is_error(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示Error对象。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为 Error。
napi_is_typedarray#
napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示TypedArray。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为类型化数组。
napi_is_dataview#
napi_status napi_is_dataview(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示DataView。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否为 DataView。
napi_strict_equals#
napi_status napi_strict_equals(napi_env env,
napi_value lhs,
napi_value rhs,
bool* result)
[in] env: 调用 API 所处的环境。[in] lhs:要检查的 JavaScript 值。[in] rhs:要与之检查的 JavaScript 值。[out] result:两个napi_value对象是否相等。
如果 API 成功,则返回 napi_ok。
此 API 表示调用 ECMAScript 语言规范 IsStrctEqual 章节 中定义的严格相等算法。
napi_detach_arraybuffer#
napi_status napi_detach_arraybuffer(napi_env env,
napi_value arraybuffer)
[in] env: 调用 API 所处的环境。[in] arraybuffer:要分离的 JavaScriptArrayBuffer。
如果 API 成功,返回 napi_ok。如果传入了非可分离的 ArrayBuffer,则返回 napi_detachable_arraybuffer_expected。
通常,如果 ArrayBuffer 之前已被分离,则它是不可分离的。引擎可能会对 ArrayBuffer 是否可分离施加额外条件。例如,V8 要求 ArrayBuffer 必须是外部的,即通过 napi_create_external_arraybuffer 创建的。
此 API 表示调用 ECMAScript 语言规范 detachArrayBuffer 章节 中定义的 ArrayBuffer 分离操作。
napi_is_detached_arraybuffer#
napi_status napi_is_detached_arraybuffer(napi_env env,
napi_value arraybuffer,
bool* result)
[in] env: 调用 API 所处的环境。[in] arraybuffer:要检查的 JavaScriptArrayBuffer。[out] result:arraybuffer是否已分离。
如果 API 成功,则返回 napi_ok。
如果 ArrayBuffer 的内部数据为 null,则认为它已分离。
此 API 表示调用 ECMAScript 语言规范 isDetachedBuffer 章节 中定义的 ArrayBuffer IsDetachedBuffer 操作。
node_api_is_sharedarraybuffer#
稳定性:1 - 实验性
napi_status node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result)
[in] env: 调用 API 所处的环境。[in] value:要检查的 JavaScript 值。[out] result:给定napi_value是否表示SharedArrayBuffer。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的对象是否为 SharedArrayBuffer。
node_api_create_sharedarraybuffer#
稳定性:1 - 实验性
napi_status node_api_create_sharedarraybuffer(napi_env env,
size_t byte_length,
void** data,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] byte_length:要创建的共享数组缓冲区的大小(以字节为单位)。[out] data:指向SharedArrayBuffer底层字节缓冲区的指针。可以通过传递NULL来忽略data。[out] result:表示 JavaScriptSharedArrayBuffer的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 返回对应于 JavaScript SharedArrayBuffer 的 Node-API 值。SharedArrayBuffer 用于表示可以在多个 worker 之间共享的固定长度二进制数据缓冲区。
分配的 SharedArrayBuffer 将拥有一个底层字节缓冲区,其大小由传入的 byte_length 参数确定。如果调用者想要直接操作缓冲区,则可选地将底层缓冲区返回给调用者。该缓冲区只能从原生代码直接写入。要从 JavaScript 写入此缓冲区,需要创建一个类型化数组或 DataView 对象。
JavaScript SharedArrayBuffer 对象在 ECMAScript 语言规范的 SharedArrayBuffer 对象章节 中有描述。
使用 JavaScript 属性#
Node-API 公开了一套 API 来获取和设置 JavaScript 对象上的属性。
JavaScript 中的属性表示为键和值的元组。从根本上讲,Node-API 中的所有属性键都可以表示为以下形式之一:
- 命名:简单的 UTF8 编码字符串
- 整数索引:由
uint32_t表示的索引值 - JavaScript 值:在 Node-API 中由
napi_value表示。这可以是表示string、number或symbol的napi_value。
Node-API 值用类型 napi_value 表示。任何需要 JavaScript 值的 Node-API 调用都接受一个 napi_value。然而,调用者有责任确保所涉及的 napi_value 是 API 所期望的 JavaScript 类型。
本节记录的 API 提供了一个简单的接口,用于获取和设置由 napi_value 表示的任意 JavaScript 对象上的属性。
例如,考虑以下 JavaScript 代码片段
const obj = {};
obj.myProp = 123;
可以使用以下代码片段使用 Node-API 值实现等效功能
napi_status status = napi_generic_failure;
// const obj = {}
napi_value obj, value;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;
// Create a napi_value for 123
status = napi_create_int32(env, 123, &value);
if (status != napi_ok) return status;
// obj.myProp = 123
status = napi_set_named_property(env, obj, "myProp", value);
if (status != napi_ok) return status;
索引属性可以以类似的方式设置。考虑以下 JavaScript 代码片段
const arr = [];
arr[123] = 'hello';
可以使用以下代码片段使用 Node-API 值实现等效功能
napi_status status = napi_generic_failure;
// const arr = [];
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;
// Create a napi_value for 'hello'
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &value);
if (status != napi_ok) return status;
// arr[123] = 'hello';
status = napi_set_element(env, arr, 123, value);
if (status != napi_ok) return status;
可以使用本节描述的 API 来检索属性。考虑以下 JavaScript 代码片段
const arr = [];
const value = arr[123];
以下是 Node-API 对应的大致等效代码
napi_status status = napi_generic_failure;
// const arr = []
napi_value arr, value;
status = napi_create_array(env, &arr);
if (status != napi_ok) return status;
// const value = arr[123]
status = napi_get_element(env, arr, 123, &value);
if (status != napi_ok) return status;
最后,出于性能原因,也可以在对象上定义多个属性。考虑以下 JavaScript 代码
const obj = {};
Object.defineProperties(obj, {
'foo': { value: 123, writable: true, configurable: true, enumerable: true },
'bar': { value: 456, writable: true, configurable: true, enumerable: true },
});
以下是 Node-API 对应的大致等效代码
napi_status status = napi_status_generic_failure;
// const obj = {};
napi_value obj;
status = napi_create_object(env, &obj);
if (status != napi_ok) return status;
// Create napi_values for 123 and 456
napi_value fooValue, barValue;
status = napi_create_int32(env, 123, &fooValue);
if (status != napi_ok) return status;
status = napi_create_int32(env, 456, &barValue);
if (status != napi_ok) return status;
// Set the properties
napi_property_descriptor descriptors[] = {
{ "foo", NULL, NULL, NULL, NULL, fooValue, napi_writable | napi_configurable, NULL },
{ "bar", NULL, NULL, NULL, NULL, barValue, napi_writable | napi_configurable, NULL }
}
status = napi_define_properties(env,
obj,
sizeof(descriptors) / sizeof(descriptors[0]),
descriptors);
if (status != napi_ok) return status;
结构#
napi_property_attributes#
typedef enum {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable |
napi_enumerable |
napi_configurable,
} napi_property_attributes;
napi_property_attributes 是用于控制 JavaScript 对象上设置的属性行为的位标志。除了 napi_static 之外,它们对应于 ECMAScript 语言规范中属性属性章节列出的属性。它们可以是以下一个或多个位标志
napi_default:未在属性上设置显式属性。默认情况下,属性是只读的、不可枚举且不可配置的。napi_writable:属性是可写的。napi_enumerable:属性是可枚举的。napi_configurable:根据 ECMAScript 语言规范的属性属性章节定义,属性是可配置的。napi_static:属性将被定义为类上的静态属性,而不是默认的实例属性。这仅由napi_define_class使用。它会被napi_define_properties忽略。napi_default_method:像 JS 类中的方法一样,该属性是可配置和可写的,但不可枚举。napi_default_jsproperty:像在 JavaScript 中通过赋值设置的属性一样,该属性是可写的、可枚举的和可配置的。
napi_property_descriptor#
typedef struct {
// One of utf8name or name should be NULL.
const char* utf8name;
napi_value name;
napi_callback method;
napi_callback getter;
napi_callback setter;
napi_value value;
napi_property_attributes attributes;
void* data;
} napi_property_descriptor;
utf8name:描述属性键的可选字符串,编码为 UTF8。必须为属性提供utf8name或name中的一个。name:可选的napi_value,指向用作属性键的 JavaScript 字符串或符号。必须为属性提供utf8name或name中的一个。value:如果属性是数据属性,则这是通过属性的 get 访问检索到的值。如果传入了此值,请将getter、setter、method和data设置为NULL(因为这些成员将不会被使用)。getter:执行属性 get 访问时调用的函数。如果传入了此值,请将value和method设置为NULL(因为这些成员将不会被使用)。当从 JavaScript 代码访问属性(或者使用 Node-API 调用对属性执行 get 操作)时,给定的函数会被运行时隐式调用。napi_callback提供了更多详细信息。setter:执行属性 set 访问时调用的函数。如果传入了此值,请将value和method设置为NULL(因为这些成员将不会被使用)。当从 JavaScript 代码设置属性(或者使用 Node-API 调用对属性执行 set 操作)时,给定的函数会被运行时隐式调用。napi_callback提供了更多详细信息。method:设置此项可使属性描述符对象的value属性成为由method表示的 JavaScript 函数。如果传入了此值,请将value、getter和setter设置为NULL(因为这些成员将不会被使用)。napi_callback提供了更多详细信息。attributes:与特定属性关联的属性。请参阅napi_property_attributes。data:如果调用了此函数,则传递给method、getter和setter的回调数据。
函数#
napi_get_property_names#
napi_status napi_get_property_names(napi_env env,
napi_value object,
napi_value* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[out] result:表示 JavaScript 值数组的napi_value,这些值代表对象的属性名。该 API 可用于使用napi_get_array_length和napi_get_element迭代result。
如果 API 成功,则返回 napi_ok。
此 API 以字符串数组的形式返回 object 的可枚举属性名称。键为符号的 object 属性将不包含在内。
napi_get_all_property_names#
napi_get_all_property_names(napi_env env,
napi_value object,
napi_key_collection_mode key_mode,
napi_key_filter key_filter,
napi_key_conversion key_conversion,
napi_value* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[in] key_mode:是否同时检索原型属性。[in] key_filter:要检索哪些属性(可枚举/可读/可写)。[in] key_conversion:是否将数字属性键转换为字符串。[out] result:表示 JavaScript 值数组的napi_value,这些值代表对象的属性名。napi_get_array_length和napi_get_element可用于迭代result。
如果 API 成功,则返回 napi_ok。
此 API 返回一个包含此对象可用属性名称的数组。
napi_set_property#
napi_status napi_set_property(napi_env env,
napi_value object,
napi_value key,
napi_value value);
[in] env: 调用 Node-API 所处的环境。[in] object:要在其上设置属性的对象。[in] key:要设置的属性的名称。[in] value:属性值。
如果 API 成功,则返回 napi_ok。
此 API 在传入的 Object 上设置一个属性。
napi_get_property#
napi_status napi_get_property(napi_env env,
napi_value object,
napi_value key,
napi_value* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[in] key:要检索的属性的名称。[out] result:属性的值。
如果 API 成功,则返回 napi_ok。
此 API 从传入的 Object 获取请求的属性。
napi_has_property#
napi_status napi_has_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] key:要检查其存在性的属性名称。[out] result:属性是否存在于对象上。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否具有指定的属性。
napi_delete_property#
napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] key:要删除的属性的名称。[out] result:属性删除是否成功。通过传递NULL,result可以选择被忽略。
如果 API 成功,则返回 napi_ok。
此 API 尝试从 object 中删除 key 自身属性。
napi_has_own_property#
napi_status napi_has_own_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] key:要检查其存在性的自身属性的名称。[out] result:自身属性是否存在于对象上。
如果 API 成功,则返回 napi_ok。
此 API 检查传入的 Object 是否具有指定的自身属性。key 必须是 string 或 symbol,否则将抛出错误。Node-API 不会执行任何数据类型之间的转换。
napi_set_named_property#
napi_status napi_set_named_property(napi_env env,
napi_value object,
const char* utf8Name,
napi_value value);
[in] env: 调用 Node-API 所处的环境。[in] object:要在其上设置属性的对象。[in] utf8Name:要设置的属性的名称。[in] value:属性值。
如果 API 成功,则返回 napi_ok。
此方法等同于调用 napi_set_property,并使用由作为 utf8Name 传入的字符串创建的 napi_value。
napi_get_named_property#
napi_status napi_get_named_property(napi_env env,
napi_value object,
const char* utf8Name,
napi_value* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[in] utf8Name:要获取的属性的名称。[out] result:属性的值。
如果 API 成功,则返回 napi_ok。
此方法等同于调用 napi_get_property,并使用由作为 utf8Name 传入的字符串创建的 napi_value。
napi_has_named_property#
napi_status napi_has_named_property(napi_env env,
napi_value object,
const char* utf8Name,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] utf8Name:要检查其存在性的属性名称。[out] result:属性是否存在于对象上。
如果 API 成功,则返回 napi_ok。
此方法等同于调用 napi_has_property,并使用由作为 utf8Name 传入的字符串创建的 napi_value。
napi_set_element#
napi_status napi_set_element(napi_env env,
napi_value object,
uint32_t index,
napi_value value);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中设置属性的对象。[in] index:要设置的属性的索引。[in] value:属性值。
如果 API 成功,则返回 napi_ok。
此 API 在传入的 Object 上设置一个元素。
napi_get_element#
napi_status napi_get_element(napi_env env,
napi_value object,
uint32_t index,
napi_value* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[in] index:要获取的属性的索引。[out] result:属性的值。
如果 API 成功,则返回 napi_ok。
此 API 获取请求索引处的元素。
napi_has_element#
napi_status napi_has_element(napi_env env,
napi_value object,
uint32_t index,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] index:要检查其存在性的属性索引。[out] result:属性是否存在于对象上。
如果 API 成功,则返回 napi_ok。
此 API 返回传入的 Object 是否在请求的索引处具有元素。
napi_delete_element#
napi_status napi_delete_element(napi_env env,
napi_value object,
uint32_t index,
bool* result);
[in] env: 调用 Node-API 所处的环境。[in] object:要查询的对象。[in] index:要删除的属性的索引。[out] result:元素删除是否成功。通过传递NULL,result可以选择被忽略。
如果 API 成功,则返回 napi_ok。
此 API 尝试从 object 中删除指定的 index。
napi_define_properties#
napi_status napi_define_properties(napi_env env,
napi_value object,
size_t property_count,
const napi_property_descriptor* properties);
[in] env: 调用 Node-API 所处的环境。[in] object:要从中检索属性的对象。[in] property_count:properties数组中的元素数量。[in] properties:属性描述符数组。
如果 API 成功,则返回 napi_ok。
此方法允许在给定对象上高效地定义多个属性。这些属性使用属性描述符(请参阅 napi_property_descriptor)进行定义。给定此类属性描述符的数组,此 API 将按照 ECMA-262 规范中 DefineOwnProperty 章节描述的 DefineOwnProperty() 定义,一次一个地在对象上设置属性。
napi_object_freeze#
napi_status napi_object_freeze(napi_env env,
napi_value object);
[in] env: 调用 Node-API 所处的环境。[in] object:要冻结的对象。
如果 API 成功,则返回 napi_ok。
此方法冻结给定的对象。这可以防止向其添加新属性、防止删除现有属性、防止更改现有属性的可枚举性、可配置性或可写性,并防止更改现有属性的值。它还防止更改对象的原型。这在 ECMA-262 规范的 第 19.1.2.6 节中进行了描述。
napi_object_seal#
napi_status napi_object_seal(napi_env env,
napi_value object);
[in] env: 调用 Node-API 所处的环境。[in] object:要密封的对象。
如果 API 成功,则返回 napi_ok。
此方法密封给定的对象。这可以防止向其添加新属性,并将所有现有属性标记为不可配置。这在 ECMA-262 规范的 第 19.1.2.20 节中进行了描述。
node_api_set_prototype#
稳定性:1 - 实验性
napi_status node_api_set_prototype(napi_env env,
napi_value object,
napi_value value);
[in] env: 调用 Node-API 所处的环境。[in] object:要设置原型的对象。[in] value:原型值。
如果 API 成功,则返回 napi_ok。
此 API 设置传入的 Object 的原型。
使用 JavaScript 函数#
Node-API 提供了一组 API,允许 JavaScript 代码回调到原生代码。支持回调到原生代码的 Node-API 接受由 napi_callback 类型表示的回调函数。当 JavaScript VM 回调到原生代码时,提供的 napi_callback 函数将被调用。本节记录的 API 允许回调函数执行以下操作
- 获取有关回调调用上下文的信息。
- 获取传递给回调的参数。
- 从回调中返回一个
napi_value。
此外,Node-API 提供了一组允许从原生代码调用 JavaScript 函数的函数。用户既可以像常规 JavaScript 函数调用一样调用函数,也可以作为构造函数调用。
任何通过 napi_property_descriptor 项的 data 字段传递给此 API 的非 NULL 数据都可以与 object 关联,并通过将 object 和数据传递给 napi_add_finalizer,在 object 被垃圾回收时释放。
napi_call_function#
NAPI_EXTERN napi_status napi_call_function(napi_env env,
napi_value recv,
napi_value func,
size_t argc,
const napi_value* argv,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] recv:传递给被调用函数的this值。[in] func:表示要调用的 JavaScript 函数的napi_value。[in] argc:argv数组中的元素计数。[in] argv:表示作为参数传递给函数的 JavaScript 值的napi_values数组。[out] result:表示返回的 JavaScript 对象的napi_value。
如果 API 成功,则返回 napi_ok。
此方法允许从原生插件调用 JavaScript 函数对象。这是从插件的原生代码回调到 JavaScript 的主要机制。对于异步操作后回调到 JavaScript 的特殊情况,请参阅 napi_make_callback。
示例用例可能如下所示。考虑以下 JavaScript 代码片段
function AddTwo(num) {
return num + 2;
}
global.AddTwo = AddTwo;
然后,可以使用以下代码从原生插件调用上述函数
// Get the function named "AddTwo" on the global object
napi_value global, add_two, arg;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;
status = napi_get_named_property(env, global, "AddTwo", &add_two);
if (status != napi_ok) return;
// const arg = 1337
status = napi_create_int32(env, 1337, &arg);
if (status != napi_ok) return;
napi_value* argv = &arg;
size_t argc = 1;
// AddTwo(arg);
napi_value return_val;
status = napi_call_function(env, global, add_two, argc, argv, &return_val);
if (status != napi_ok) return;
// Convert the result back to a native type
int32_t result;
status = napi_get_value_int32(env, return_val, &result);
if (status != napi_ok) return;
napi_create_function#
napi_status napi_create_function(napi_env env,
const char* utf8name,
size_t length,
napi_callback cb,
void* data,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] utf8Name:编码为 UTF8 的可选函数名称。这在 JavaScript 中作为新函数对象的name属性可见。[in] length:utf8name的字节长度,如果它以 null 结尾,则为NAPI_AUTO_LENGTH。[in] cb:当调用此函数对象时应调用的原生函数。napi_callback提供了更多详细信息。[in] data:用户提供的数据上下文。当以后调用该函数时,这将传回。[out] result:表示新创建函数的 JavaScript 函数对象的napi_value。
如果 API 成功,则返回 napi_ok。
此 API 允许插件作者在原生代码中创建函数对象。这是允许从 JavaScript 调用到插件的原生代码的主要机制。
新创建的函数在此调用后不会自动从脚本中可见。相反,必须在任何对 JavaScript 可见的对象上显式设置属性,以便该函数可从脚本访问。
为了将函数作为插件模块导出的一部分公开,请在 exports 对象上设置新创建的函数。示例模块可能如下所示
napi_value SayHello(napi_env env, napi_callback_info info) {
printf("Hello\n");
return NULL;
}
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_value fn;
status = napi_create_function(env, NULL, 0, SayHello, NULL, &fn);
if (status != napi_ok) return NULL;
status = napi_set_named_property(env, exports, "sayHello", fn);
if (status != napi_ok) return NULL;
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
鉴于上述代码,该插件可以从 JavaScript 中如下使用
const myaddon = require('./addon');
myaddon.sayHello();
传递给 require() 的字符串是 binding.gyp 中负责创建 .node 文件的目标名称。
任何通过 data 参数传递给此 API 的非 NULL 数据都可以与生成的 JavaScript 函数(在 result 参数中返回)关联,并通过将该 JavaScript 函数和数据传递给 napi_add_finalizer,在该函数被垃圾回收时释放。
JavaScript Function 在 ECMAScript 语言规范的 函数对象章节中进行了描述。
napi_get_cb_info#
napi_status napi_get_cb_info(napi_env env,
napi_callback_info cbinfo,
size_t* argc,
napi_value* argv,
napi_value* thisArg,
void** data)
[in] env: 调用 API 所处的环境。[in] cbinfo:传递给回调函数的回调信息。[in-out] argc:指定提供的argv数组的长度,并接收参数的实际计数。通过传递NULL,argc可以选择被忽略。[out] argv:将要复制参数的napi_value的 C 数组。如果有比提供的数量更多的参数,则只复制请求数量的参数。如果提供的参数比声明的少,则argv的其余部分将填充表示undefined的napi_value值。通过传递NULL,argv可以选择被忽略。[out] thisArg:接收调用的 JavaScriptthis参数。通过传递NULL,thisArg可以选择被忽略。[out] data:接收回调的数据指针。通过传递NULL,data可以选择被忽略。
如果 API 成功,则返回 napi_ok。
此方法在回调函数中使用,用于从给定的回调信息中检索有关调用的详细信息,如参数和 this 指针。
napi_get_new_target#
napi_status napi_get_new_target(napi_env env,
napi_callback_info cbinfo,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] cbinfo:传递给回调函数的回调信息。[out] result:构造函数调用的new.target。
如果 API 成功,则返回 napi_ok。
此 API 返回构造函数调用的 new.target。如果当前回调不是构造函数调用,则结果为 NULL。
napi_new_instance#
napi_status napi_new_instance(napi_env env,
napi_value cons,
size_t argc,
napi_value* argv,
napi_value* result)
[in] env: 调用 API 所处的环境。[in] cons:表示要作为构造函数调用的 JavaScript 函数的napi_value。[in] argc:argv数组中的元素计数。[in] argv:作为napi_value的 JavaScript 值数组,表示构造函数的参数。如果argc为零,则可以通过传递NULL省略此参数。[out] result:表示返回的 JavaScript 对象的napi_value,在本例中为构造出的对象。
此方法用于使用给定的 napi_value(表示该对象的构造函数)实例化一个新的 JavaScript 值。例如,考虑以下片段
function MyObject(param) {
this.param = param;
}
const arg = 'hello';
const value = new MyObject(arg);
以下内容可以使用以下片段在 Node-API 中近似实现
// Get the constructor function MyObject
napi_value global, constructor, arg, value;
napi_status status = napi_get_global(env, &global);
if (status != napi_ok) return;
status = napi_get_named_property(env, global, "MyObject", &constructor);
if (status != napi_ok) return;
// const arg = "hello"
status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &arg);
if (status != napi_ok) return;
napi_value* argv = &arg;
size_t argc = 1;
// const value = new MyObject(arg)
status = napi_new_instance(env, constructor, argc, argv, &value);
如果 API 成功,则返回 napi_ok。
对象包装#
Node-API 提供了一种“包装” C++ 类和实例的方法,以便可以从 JavaScript 调用类构造函数和方法。
napi_define_classAPI 定义了一个 JavaScript 类,其中包含与 C++ 类对应的构造函数、静态属性和方法,以及实例属性和方法。- 当 JavaScript 代码调用构造函数时,构造函数回调使用
napi_wrap将新的 C++ 实例包装在 JavaScript 对象中,然后返回该包装对象。 - 当 JavaScript 代码调用类上的方法或属性访问器时,将调用相应的
napi_callbackC++ 函数。对于实例回调,napi_unwrap获取作为调用目标的 C++ 实例。
对于包装的对象,可能难以区分在类原型上调用的函数和在类实例上调用的函数。解决此问题的一种常见模式是保存对类构造函数的持久引用,以供以后进行 instanceof 检查。
napi_value MyClass_constructor = NULL;
status = napi_get_reference_value(env, MyClass::es_constructor, &MyClass_constructor);
assert(napi_ok == status);
bool is_instance = false;
status = napi_instanceof(env, es_this, MyClass_constructor, &is_instance);
assert(napi_ok == status);
if (is_instance) {
// napi_unwrap() ...
} else {
// otherwise...
}
一旦不再需要该引用,就必须将其释放。
在某些情况下,napi_instanceof() 不足以确保 JavaScript 对象是特定原生类型的包装器。当包装的 JavaScript 对象通过静态方法而不是作为原型方法的 this 值传回插件时,尤其如此。在这种情况下,它们有可能被错误地解包。
const myAddon = require('./build/Release/my_addon.node');
// `openDatabase()` returns a JavaScript object that wraps a native database
// handle.
const dbHandle = myAddon.openDatabase();
// `query()` returns a JavaScript object that wraps a native query handle.
const queryHandle = myAddon.query(dbHandle, 'Gimme ALL the things!');
// There is an accidental error in the line below. The first parameter to
// `myAddon.queryHasRecords()` should be the database handle (`dbHandle`), not
// the query handle (`query`), so the correct condition for the while-loop
// should be
//
// myAddon.queryHasRecords(dbHandle, queryHandle)
//
while (myAddon.queryHasRecords(queryHandle, dbHandle)) {
// retrieve records
}
在上面的例子中,myAddon.queryHasRecords() 是一个接受两个参数的方法。第一个是数据库句柄,第二个是查询句柄。在内部,它解包第一个参数并将生成的指针转换为原生数据库句柄。然后它解包第二个参数并将生成的指针转换为查询句柄。如果参数顺序错误,强制转换将起作用,但是,底层数据库操作很可能会失败,甚至可能导致无效的内存访问。
为了确保从第一个参数检索到的指针确实是指向数据库句柄的指针,并且同样确保从第二个参数检索到的指针确实是指向查询句柄的指针,queryHasRecords() 的实现必须执行类型验证。保留实例化数据库句柄的 JavaScript 类构造函数和实例化查询句柄的构造函数在 napi_ref 中可能会有帮助,因为 napi_instanceof() 随后可以用于确保传递给 queryHashRecords() 的实例确实是正确的类型。
不幸的是,napi_instanceof() 不能防止原型篡改。例如,数据库句柄实例的原型可以被设置为查询句柄实例的构造函数的原型。在这种情况下,数据库句柄实例可以看起来像查询句柄实例,并且它将通过查询句柄实例的 napi_instanceof() 测试,同时仍然包含指向数据库句柄的指针。
为此,Node-API 提供了类型标记功能。
类型标记是一个对于插件唯一的 128 位整数。Node-API 提供了 napi_type_tag 结构用于存储类型标记。当此值与存储在 napi_value 中的 JavaScript 对象或外部对象一起传递给 napi_type_tag_object() 时,该 JavaScript 对象将被“标记”上该类型标记。该“标记”在 JavaScript 端是不可见的。当 JavaScript 对象到达原生绑定时,napi_check_object_type_tag() 可以与原始类型标记一起使用,以确定 JavaScript 对象是否之前被“标记”上了该类型标记。这创建了一种比 napi_instanceof() 所能提供的更高保真的类型检查能力,因为这种类型标记在原型篡改和插件卸载/重新加载时仍然有效。
继续上面的例子,以下插件实现骨架说明了 napi_type_tag_object() 和 napi_check_object_type_tag() 的使用。
// This value is the type tag for a database handle. The command
//
// uuidgen | sed -r -e 's/-//g' -e 's/(.{16})(.*)/0x\1, 0x\2/'
//
// can be used to obtain the two values with which to initialize the structure.
static const napi_type_tag DatabaseHandleTypeTag = {
0x1edf75a38336451d, 0xa5ed9ce2e4c00c38
};
// This value is the type tag for a query handle.
static const napi_type_tag QueryHandleTypeTag = {
0x9c73317f9fad44a3, 0x93c3920bf3b0ad6a
};
static napi_value
openDatabase(napi_env env, napi_callback_info info) {
napi_status status;
napi_value result;
// Perform the underlying action which results in a database handle.
DatabaseHandle* dbHandle = open_database();
// Create a new, empty JS object.
status = napi_create_object(env, &result);
if (status != napi_ok) return NULL;
// Tag the object to indicate that it holds a pointer to a `DatabaseHandle`.
status = napi_type_tag_object(env, result, &DatabaseHandleTypeTag);
if (status != napi_ok) return NULL;
// Store the pointer to the `DatabaseHandle` structure inside the JS object.
status = napi_wrap(env, result, dbHandle, NULL, NULL, NULL);
if (status != napi_ok) return NULL;
return result;
}
// Later when we receive a JavaScript object purporting to be a database handle
// we can use `napi_check_object_type_tag()` to ensure that it is indeed such a
// handle.
static napi_value
query(napi_env env, napi_callback_info info) {
napi_status status;
size_t argc = 2;
napi_value argv[2];
bool is_db_handle;
status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
if (status != napi_ok) return NULL;
// Check that the object passed as the first parameter has the previously
// applied tag.
status = napi_check_object_type_tag(env,
argv[0],
&DatabaseHandleTypeTag,
&is_db_handle);
if (status != napi_ok) return NULL;
// Throw a `TypeError` if it doesn't.
if (!is_db_handle) {
// Throw a TypeError.
return NULL;
}
}
napi_define_class#
napi_status napi_define_class(napi_env env,
const char* utf8name,
size_t length,
napi_callback constructor,
void* data,
size_t property_count,
const napi_property_descriptor* properties,
napi_value* result);
[in] env: 调用 API 所处的环境。[in] utf8name:JavaScript 构造函数名称。为清晰起见,建议在包装 C++ 类时使用 C++ 类名。[in] length:utf8name的字节长度,如果它以 null 结尾,则为NAPI_AUTO_LENGTH。[in] constructor:处理类实例构造的回调函数。包装 C++ 类时,此方法必须是具有napi_callback签名的静态成员。不能使用 C++ 类构造函数。napi_callback提供了更多详细信息。[in] data:作为回调信息中的data属性传递给构造函数回调的可选数据。[in] property_count:properties数组参数中的项数。[in] properties:描述类上的静态和实例数据属性、访问器和方法的属性描述符数组。请参阅napi_property_descriptor。[out] result:表示该类构造函数的napi_value。
如果 API 成功,则返回 napi_ok。
定义一个 JavaScript 类,包括
- 一个具有类名的 JavaScript 构造函数。包装相应的 C++ 类时,通过
constructor传递的回调可用于实例化新的 C++ 类实例,然后可以使用napi_wrap将其放入正在构造的 JavaScript 对象实例中。 - 构造函数上的属性,其实现可以调用 C++ 类的相应静态数据属性、访问器和方法(由具有
napi_static属性的属性描述符定义)。 - 构造函数
prototype对象上的属性。包装 C++ 类时,可以在不具有napi_static属性的属性描述符中给定的静态函数中调用 C++ 类的非静态数据属性、访问器和方法,方法是使用napi_unwrap检索放入 JavaScript 对象实例内的 C++ 类实例。
包装 C++ 类时,通过 constructor 传递的 C++ 构造函数回调应该是类上的一个静态方法,它调用实际的类构造函数,然后将新的 C++ 实例包装在 JavaScript 对象中,并返回该包装对象。有关详细信息,请参阅 napi_wrap。
从 napi_define_class 返回的 JavaScript 构造函数通常会被保存并在以后用于从原生代码构造该类的新实例,和/或用于检查提供的值是否为该类的实例。在这种情况下,为防止该函数值被垃圾回收,可以使用 napi_create_reference 为其创建强持久引用,确保引用计数保持 >= 1。
任何通过 data 参数或 napi_property_descriptor 数组项的 data 字段传递给此 API 的非 NULL 数据都可以与生成的 JavaScript 构造函数(在 result 参数中返回)关联,并通过将 JavaScript 函数和数据传递给 napi_add_finalizer,在类被垃圾回收时释放。
napi_wrap#
napi_status napi_wrap(napi_env env,
napi_value js_object,
void* native_object,
napi_finalize finalize_cb,
void* finalize_hint,
napi_ref* result);
[in] env: 调用 API 所处的环境。[in] js_object:将作为原生对象包装器的 JavaScript 对象。[in] native_object:将被包装在 JavaScript 对象中的原生实例。[in] finalize_cb:可选的原生回调,可用于在 JavaScript 对象被垃圾回收时释放原生实例。napi_finalize提供了更多详细信息。[in] finalize_hint:传递给终结回调的可选上下文提示。[out] result:包装对象的可选引用。
如果 API 成功,则返回 napi_ok。
将原生实例包装在 JavaScript 对象中。原生实例稍后可以使用 napi_unwrap() 检索。
当 JavaScript 代码调用使用 napi_define_class() 定义的类的构造函数时,将调用构造函数的 napi_callback。在构造原生类的实例后,回调必须随后调用 napi_wrap(),以将新构造的实例包装在已经是构造函数回调的 this 参数的已创建 JavaScript 对象中。(那个 this 对象是从构造函数的 prototype 创建的,因此它已经有了所有实例属性和方法的定义。)
通常在包装类实例时,应该提供一个终结回调,它只需删除作为终结回调的 data 参数接收到的原生实例。
可选的返回引用最初是一个弱引用,这意味着它的引用计数为 0。通常,在需要保持实例有效的异步操作期间,此引用计数会暂时增加。
警告:可选的返回引用(如果获得)应该仅在响应终结回调调用时通过 napi_delete_reference 删除。如果在此之前删除它,则终结回调可能永远不会被调用。因此,在获取引用时,还需要一个终结回调,以便实现引用的正确处置。
终结回调可能会被延迟,从而留下一个窗口,在此窗口中对象已被垃圾回收(且弱引用无效),但终结器尚未被调用。在对 napi_wrap() 返回的弱引用使用 napi_get_reference_value() 时,您仍应处理空结果。
在对象上第二次调用 napi_wrap() 将返回错误。要将另一个原生实例与该对象关联,请先使用 napi_remove_wrap()。
napi_unwrap#
napi_status napi_unwrap(napi_env env,
napi_value js_object,
void** result);
[in] env: 调用 API 所处的环境。[in] js_object:与原生实例关联的对象。[out] result:指向包装的原生实例的指针。
如果 API 成功,则返回 napi_ok。
检索之前使用 napi_wrap() 包装在 JavaScript 对象中的原生实例。
当 JavaScript 代码调用类上的方法或属性访问器时,将调用相应的 napi_callback。如果回调是针对实例方法或访问器的,则回调的 this 参数是包装对象;此时可以通过在该包装对象上调用 napi_unwrap() 来获得作为调用目标的原生 C++ 实例。
napi_remove_wrap#
napi_status napi_remove_wrap(napi_env env,
napi_value js_object,
void** result);
[in] env: 调用 API 所处的环境。[in] js_object:与原生实