1# 使用Node-API接口进行错误处理开发 2 3## 简介 4 5使用Node-API接口进行错误处理开发,使得在Node-API模块中能够更好地管理和响应错误情况。通过合理使用这些函数,可以提高模块的稳定性和可靠性。 6 7## 基本概念 8 9在ArkTS编程中,异常和错误是常见的概念。异常表示发生了某种意外情况,而错误则指示程序无法正确执行某些操作。Node-API提供了一系列方法来帮助开发者在Node-API模块中处理ArkTS中的异常和错误。下面是一些基本概念: 10 11- **异常(Exception)**:在程序执行过程中可能会出现的意外情况,可以是语法错误、运行时错误或逻辑错误,例如除以零或对未定义变量的操作。 12- **错误(Error)**:表示程序无法顺利执行某些操作,可以是由底层系统、API函数或开发者自定义的。 13- **类型错误(Type Error)**:表示操作或值的类型不符合预期的情况,通常是由于错误的数据类型导致的。 14- **范围错误(Range Error)**:表示一个值不在预期的范围内,例如对数组长度之外的索引进行访问。 15 16这些基本概念在异常和错误处理中非常重要,开发者需要通过适当的方法来捕获、处理或向用户报告这些异常和错误,以确保程序的稳定性和正确性。Node-API提供的方法可以帮助开发者在Node-API模块中处理ArkTS中的异常和错误。 17 18## 场景和功能介绍 19 20以下Node-API接口主要用于与ArkTS交互时处理错误和异常情况。他们的使用场景如下: 21| 接口 | 描述 | 22| -------- | -------- | 23| napi_create_error、napi_create_type_error、napi_create_range_error | 在C/C++中需要创建一个错误对象时,可以使用这些函数。创建的错误对象可以使用napi_throw抛出到ArkTS | 24| napi_throw | 当在C/C++中出现了错误或异常情况时,通过使用napi_create_error或napi_get_last_error_info方法创建或获取ArkTS Error对象,使用该方法抛出已有的ArkTS Error对象。 | 25| napi_throw_error、napi_throw_type_error、napi_throw_range_error | 当在C/C++中出现了错误或异常情况时,可以使用这些函数来抛出ArkTS中的异常。 | 26| napi_is_error | 检查一个napi_value是否代表一个错误对象时,可以使用这个函数。 | 27| napi_get_and_clear_last_exception | 当你需要获取最近一次出现的异常,并将异常队列清空时,可以使用这个函数。 | 28| napi_is_exception_pending | 当你需要判断是否有未处理的异常时,可以使用这个函数。 | 29| napi_fatal_error | 当遇到严重错误或不可恢复的情况时,可以使用这个函数引发致命错误来立即终止进程。 | 30| napi_fatal_exception | 抛出一个致命异常并终止进程, 同时产生相应的crash日志。| 31 32## 使用示例 33 34Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](use-napi-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。 35 36### napi_get_last_error_info 37 38用于获取最后一次发生的错误信息,包括错误码、错误消息以及错误进栈信息,即使存在挂起的ArkTS异常,也可以调用此API。 39 40cpp部分代码 41 42```cpp 43#include "napi/native_api.h" 44#include <assert.h> 45static napi_value GetLastErrorInfo(napi_env env, napi_callback_info info) 46{ 47 // 获取输入参数(这里以字符串message作为参数传入) 48 size_t argc = 1; 49 napi_value args[1] = {nullptr}; 50 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 51 // 将传入的字符串参数以napi_get_value_int32取出,主动制造错误 52 int32_t value = 0; 53 napi_status status = napi_get_value_int32(env, args[0], &value); 54 // 接口使用错误,故返回值不为napi_ok 55 assert(status != napi_ok); 56 // 调用接口napi_get_last_error_info获取最后一次错误信息 57 const napi_extended_error_info *errorInfo; 58 napi_get_last_error_info(env, &errorInfo); 59 // 取出错误码与接口调用错误后其返回值作比较 60 assert(errorInfo->error_code == status); 61 // 取出错误消息作为返回值带出去打印 62 napi_value result = nullptr; 63 napi_create_string_utf8(env, errorInfo->error_message, NAPI_AUTO_LENGTH, &result); 64 return result; 65} 66``` 67 68接口声明 69 70```ts 71// index.d.ts 72export const getLastErrorInfo: (str: string) => string; 73``` 74 75ArkTS侧示例代码 76 77```ts 78import hilog from '@ohos.hilog' 79import testNapi from 'libentry.so' 80try { 81 hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_last_error_info: %{public}s', testNapi.getLastErrorInfo('message')); 82} catch (error) { 83 hilog.error(0x0000, 'testTag', 'Test Node-API napi_get_last_error_info error: %{public}s', error); 84} 85``` 86 87### napi_create_type_error 88 89创建并获取一个带文本信息的ArkTS TypeError。 90 91cpp部分代码 92 93```cpp 94#include "napi/native_api.h" 95 96static napi_value CreateTypeError(napi_env env, napi_callback_info info) 97{ 98 // 构造errorCode和errorMessage 99 napi_value errorCode = nullptr; 100 napi_create_string_utf8(env, "napi_create_error errorCode", NAPI_AUTO_LENGTH, &errorCode); 101 napi_value errorMessage = nullptr; 102 napi_create_string_utf8(env, "napi_create_error errorMessage", NAPI_AUTO_LENGTH, &errorMessage); 103 // 调用napi_create_type_error创建一个typeError错误对象 104 napi_value error = nullptr; 105 napi_create_type_error(env, errorCode, errorMessage, &error); 106 return error; 107} 108``` 109 110接口声明 111 112```ts 113// index.d.ts 114export const createTypeError: () => Error; 115``` 116 117ArkTS侧示例代码 118 119```ts 120import hilog from '@ohos.hilog' 121import testNapi from 'libentry.so' 122try { 123 throw testNapi.createTypeError(); 124} catch (error) { 125 hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_type_error errorCode: %{public}s, errorMessage %{public}s', error.code, error.message); 126} 127``` 128 129### napi_create_range_error 130 131创建并获取一个带文本信息的ArkTS RangeError。 132 133cpp部分代码 134 135```cpp 136#include "napi/native_api.h" 137 138static napi_value CreateRangeError(napi_env env, napi_callback_info info) 139{ 140 // 构造errorCode和errorMessage 141 napi_value errorCode = nullptr; 142 napi_create_string_utf8(env, "napi_create_error errorCode", NAPI_AUTO_LENGTH, &errorCode); 143 napi_value errorMessage = nullptr; 144 napi_create_string_utf8(env, "napi_create_error errorMessage", NAPI_AUTO_LENGTH, &errorMessage); 145 // 调用napi_create_range_error创建一个typeError错误对象 146 napi_value error = nullptr; 147 napi_create_range_error(env, errorCode, errorMessage, &error); 148 return error; 149} 150``` 151 152接口声明 153 154```ts 155// index.d.ts 156export const createRangeError: () => Error; 157``` 158 159ArkTS侧示例代码 160 161```ts 162import hilog from '@ohos.hilog' 163import testNapi from 'libentry.so' 164try { 165 throw testNapi.createRangeError(); 166} catch (error) { 167 hilog.error(0x0000, 'testTag', 'Test Node-API napi_create_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 168} 169``` 170 171### napi_create_error 172 173创建并获取一个带文本信息的ArkTS Error。 174 175### napi_throw 176 177用于在Node-API模块中抛出ArkTS异常的函数。当在本机代码中发生错误或检测到不符合预期的情况时,可以使用此接口来抛出一个ArkTS异常,使其能够被捕获并处理。 178 179cpp部分代码 180 181```cpp 182#include "napi/native_api.h" 183 184static napi_value NapiThrow(napi_env env, napi_callback_info info) 185{ 186 // 代码中发生某些错误后,可执行以下操作抛出异常 187 // 在Node-API环境中创建一个字符串,并将其存储在errorCode变量中 188 napi_value errorCode = nullptr; 189 napi_create_string_utf8(env, "throw errorCode", NAPI_AUTO_LENGTH, &errorCode); 190 // 在Node-API环境中创建一个字符串,并将其存储在errorMessage变量中 191 napi_value errorMessage = nullptr; 192 napi_create_string_utf8(env, "throw errorMessage", NAPI_AUTO_LENGTH, &errorMessage); 193 // 创建一个ArkTS对象error 194 napi_value error = nullptr; 195 napi_create_error(env, errorCode, errorMessage, &error); 196 // 通过napi_throw接口将对象抛出 197 napi_throw(env, error); 198 return nullptr; 199} 200``` 201 202接口声明 203 204```ts 205// index.d.ts 206export const napiThrow: () => void; 207``` 208 209ArkTS侧示例代码 210 211```ts 212import hilog from '@ohos.hilog' 213import testNapi from 'libentry.so' 214try { 215 testNapi.napiThrow(); 216} catch (error) { 217 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 218} 219``` 220 221### napi_throw_error 222 223用于抛出一个带文本信息的ArkTS Error。 224 225cpp部分代码 226 227```cpp 228#include "napi/native_api.h" 229 230// 这里直接抛出一个带有errorMessage的错误 231static napi_value NapiThrowErrorMessage(napi_env env, napi_callback_info info) 232{ 233 napi_throw_error(env, nullptr, "napi_throw_error throwing an error"); 234 return nullptr; 235} 236// 传入两个参数,在第二个参数,也就是除数为0的时候抛出一个错误 237static napi_value NapiThrowError(napi_env env, napi_callback_info info) 238{ 239 // ArkTS侧传入两个参数 240 size_t argc = 2; 241 napi_value argv[2] = {nullptr}; 242 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 243 // 将其转换为double类型的值作为被除数和除数 244 double dividend, divisor; 245 napi_get_value_double(env, argv[0], ÷nd); 246 napi_get_value_double(env, argv[1], &divisor); 247 // 在这里判断除数如果为0则直接抛出一个错误,errorCode为:DIVIDE_BY_ZERO,errorMessage为:Cannot divide by zero 248 if (divisor == 0) { 249 napi_throw_error(env, "DIVIDE_BY_ZERO", "Cannot divide by zero"); 250 } 251 return nullptr; 252} 253``` 254 255接口声明 256 257```ts 258// index.d.ts 259export const napiThrowErrorMessage: () => void; 260export const napiThrowError: (dividend: number, divisor: number) => void; 261``` 262 263ArkTS侧示例代码 264 265```ts 266import hilog from '@ohos.hilog' 267import testNapi from 'libentry.so' 268try { 269 testNapi.napiThrowErrorMessage(); 270} catch (error) { 271 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_error error code: %{public}s , message: %{public}s', error.code, error.message); 272} 273try { 274 testNapi.napiThrowError(5, 0); 275} catch (error) { 276 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_error errorCode: %{public}s , errorManager: %{public}s', error.code, error.message); 277} 278``` 279 280### napi_throw_type_error 281 282创建并获取一个带文本信息的ArkTS TypeError。 283 284cpp部分代码 285 286```cpp 287#include "napi/native_api.h" 288 289// 这里直接抛出一个带有errorMessage的TypeError 290static napi_value ThrowTypeErrorMessage(napi_env env, napi_callback_info info) 291{ 292 napi_throw_type_error(env, nullptr, "napi_throw_type_error throwing an error"); 293 return nullptr; 294} 295// 传入一个类型不匹配的参数,判断类型不匹配之后抛出typeError 296static napi_value ThrowTypeError(napi_env env, napi_callback_info info) 297{ 298 // ArkTS侧传入一个参数 299 size_t argc = 1; 300 napi_value argv[1] = {nullptr}; 301 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 302 // 将传入参数转换为napi_valuetype类型的值 303 napi_valuetype valueType; 304 napi_typeof(env, argv[0], &valueType); 305 // 如果传入参数不为napi_number类型的值则抛出TypeError 306 if (valueType != napi_number) { 307 // 这里抛出一个既带有errorCode也带有errorMessage的TypeError 308 napi_throw_type_error(env, "napi_throw_type_error", "Argument must be a number"); 309 } 310 return nullptr; 311} 312``` 313 314接口声明 315 316```ts 317// index.d.ts 318export const throwTypeErrorMessage: () => void; 319export const throwTypeError: (message: string) => void; 320``` 321 322ArkTS侧示例代码 323 324```ts 325import hilog from '@ohos.hilog' 326import testNapi from 'libentry.so' 327try { 328 testNapi.throwTypeErrorMessage(); 329} catch (error) { 330 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_type_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 331} 332try { 333 testNapi.throwTypeError('str'); 334} catch (error) { 335 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_type_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 336} 337``` 338 339### napi_throw_range_error 340 341创建并获取一个带文本信息的ArkTS RangeError。 342 343cpp部分代码 344 345```cpp 346#include "napi/native_api.h" 347 348// 这里直接抛出一个带有errorMessage的RangeError 349static napi_value ThrowRangeErrorMessage(napi_env env, napi_callback_info info) 350{ 351 napi_throw_range_error(env, nullptr, "napi_throw_range_error one"); 352 return nullptr; 353} 354// 传入不匹配的参数个数,判断不匹配之后抛出rangeError 355static napi_value ThrowRangeError(napi_env env, napi_callback_info info) 356{ 357 // ArkTS侧传入两个参数 358 size_t argc = 2; 359 napi_value argv[2] = {nullptr}; 360 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 361 // 如果传入参数个数不为2 362 if (argc != 2) { 363 // 这里抛出一个RangeError 364 napi_throw_range_error(env, "napi_throw_range_error", "Expected two numbers as arguments"); 365 return nullptr; 366 } 367 // 下面将传入的两值相加并传出去 368 double numOne = 0; 369 double numTwo = 0; 370 napi_get_value_double(env, argv[0], &numOne); 371 napi_get_value_double(env, argv[1], &numTwo); 372 double result = numOne + numTwo; 373 napi_value resultValue; 374 napi_create_double(env, result, &resultValue); 375 return resultValue; 376} 377``` 378 379接口声明 380 381```ts 382// index.d.ts 383export const throwRangeErrorMessage: () => void; 384export const throwRangeError: (num: number) => number | void; 385``` 386 387ArkTS侧示例代码 388 389```ts 390import hilog from '@ohos.hilog' 391import testNapi from 'libentry.so' 392try { 393 testNapi.throwRangeErrorMessage(); 394} catch (error) { 395 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 396} 397 398try { 399 testNapi.throwRangeError(1); 400} catch (error) { 401 hilog.error(0x0000, 'testTag', 'Test Node-API napi_throw_range_error errorCode: %{public}s, errorMessage: %{public}s', error.code, error.message); 402} 403``` 404 405### napi_is_error 406 407用于判断给定的napi_value是否表示一个error对象。 408 409cpp部分代码 410 411```cpp 412#include "napi/native_api.h" 413 414static napi_value NapiIsError(napi_env env, napi_callback_info info) 415{ 416 // 接收一个入参 417 size_t argc = 1; 418 napi_value args[1] = {nullptr}; 419 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 420 // 调用接口napi_is_error判断入参是否为一个error对象 421 bool result = false; 422 // 如果napi_value为一个error对象,则设置result为true的布尔值,否则设置为false 423 napi_is_error(env, args[0], &result); 424 // 取出result通过napi_get_boolean接口将取出的bool值转换为napi_value类型的值返回出去 425 napi_value returnValue = nullptr; 426 napi_get_boolean(env, result, &returnValue); 427 return returnValue; 428} 429``` 430 431接口声明 432 433```ts 434// index.d.ts 435export const napiIsError: <T>(obj: T) => boolean; 436``` 437 438ArkTS侧示例代码 439 440```ts 441import hilog from '@ohos.hilog' 442import testNapi from 'libentry.so' 443try { 444 throw new Error("throwing an error"); 445} catch (error) { 446 hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_error error: %{public}s', testNapi.napiIsError(error) 447 .toString()); 448 hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_error error: %{public}s', testNapi.napiIsError(1) 449 .toString()); 450} 451``` 452 453### napi_get_and_clear_last_exception 454 455用于获取并清除最近一次出现的异常。 456 457cpp部分代码 458 459```cpp 460#include "napi/native_api.h" 461 462static napi_value GetAndClearLastException(napi_env env, napi_callback_info info) 463{ 464 // 抛出异常,创造异常情况 465 napi_throw_error(env, "napi_create_error errorCode", "napi_create_error errorMessage"); 466 // 调用napi_get_and_clear_last_exception接口获取并清除最后一个未处理的异常。即使存在挂起的ArkTS异常,也可以调用此API 467 napi_value result = nullptr; 468 napi_status status = napi_get_and_clear_last_exception(env, &result); 469 if (status != napi_ok) { 470 return nullptr; 471 } 472 return result; 473} 474``` 475 476接口声明 477 478```ts 479// index.d.ts 480export const getAndClearLastException: () => Error | void; 481``` 482 483ArkTS侧示例代码 484 485```ts 486import hilog from '@ohos.hilog' 487import testNapi from 'libentry.so' 488// 这里获取到最后一个未处理的异常 489hilog.info(0x0000, 'testTag', 'Test Node-API napi_get_and_clear_last_exception, error.message: %{public}s', 490 testNapi.getAndClearLastException()); 491``` 492 493### napi_is_exception_pending 494 495用于判断是否出现了异常。 496 497cpp部分代码 498 499```cpp 500#include "napi/native_api.h" 501 502static napi_value IsExceptionPending(napi_env env, napi_callback_info info) 503{ 504 napi_status status; 505 bool isExceptionPending = false; 506 // 在执行一些可能引发异常的操作后 507 napi_throw_error(env, "napi_create_error errorCode", "napi_create_error errorMessage"); 508 // 检查当前环境中是否有异常挂起 509 status = napi_is_exception_pending(env, &isExceptionPending); 510 if (status != napi_ok) { 511 return nullptr; 512 } 513 if (isExceptionPending) { 514 // 处理异常挂起的情况 515 napi_value result = nullptr; 516 status = napi_get_and_clear_last_exception(env, &result); 517 if (status != napi_ok) { 518 return nullptr; 519 } 520 // 将处理的异常返回出去 521 return result; 522 } 523 return nullptr; 524} 525``` 526 527接口声明 528 529```ts 530// index.d.ts 531export const isExceptionPending: () => Object | void; 532``` 533 534ArkTS侧示例代码 535 536```ts 537import hilog from '@ohos.hilog' 538import testNapi from 'libentry.so' 539interface MyObject { 540 code: string; 541 message: string; 542} 543try { 544 let result = testNapi.isExceptionPending() as MyObject; 545 hilog.info(0x0000, 'testTag', 'Test Node-API napi_is_exception_pending, error.Code: %{public}s, error.message: %{public}s', 546 result.code, result.message); 547} catch (error) { 548 hilog.error(0x0000, 'testTag', 'Test Node-API napi_is_exception_pending error'); 549} 550``` 551 552### napi_fatal_error 553 554用于引发致命错误以立即终止进程。在调用napi_fatal_error函数后,导致应用程序终止,因此应该慎重使用,避免在正常操作中频繁调用该函数。 555 556cpp部分代码 557 558```cpp 559#include "napi/native_api.h" 560 561static napi_value FatalError(napi_env env, napi_callback_info info) 562{ 563 // 请注意,使用napi_fatal_error函数会导致应用进程直接终止,因此应该谨慎使用,仅在遇到无法恢复的严重错误时才应该调用该函数 564 // 模拟一个致命错误条件 565 bool errorCondition = true; 566 if (errorCondition) { 567 // 创建一个致命错误信息 568 napi_fatal_error("napi_fatal_error test", NAPI_AUTO_LENGTH, "napi_create_error errorMessage", NAPI_AUTO_LENGTH); 569 } 570 return nullptr; 571} 572``` 573 574接口声明 575 576```ts 577// index.d.ts 578export const fatalError: () => void; 579``` 580 581ArkTS侧示例代码 582 583```ts 584import hilog from '@ohos.hilog' 585import testNapi from 'libentry.so' 586try { 587 testNapi.fatalError(); 588} catch (error) { 589 hilog.error(0x0000, 'testTag', 'Test Node-API napi_fatal_error error'); 590} 591``` 592 593### napi_fatal_exception 594在主线程的上下文环境中调用napi_fatal_exception函数后,抛出一个致命异常,导致应用程序终止,同时会生成相应的crash日志。因此应该慎重使用,避免在正常操作中频繁调用该函数。 595 596cpp部分代码 597 598```cpp 599#include "napi/native_api.h" 600 601static napi_value FatalException(napi_env env, napi_callback_info info) 602{ 603 size_t argc = 1; 604 napi_value args[1] = {nullptr}; 605 606 napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 607 if (status != napi_ok) { 608 return nullptr; 609 } 610 // 请注意,使用napi_fatal_exception函数会导致应用进程直接终止,因此应该谨慎使用,仅在主线程遇到无法恢复的严重错误时才应该调用该函数 611 // 模拟一个致命错误条件 612 status = napi_fatal_exception(env, args[0]); 613 if (status != napi_ok) { 614 return nullptr; 615 } 616 return nullptr; 617} 618``` 619 620接口声明 621 622```ts 623// index.d.ts 624export const fatalException: (err: Error) => void; 625``` 626 627ArkTS侧示例代码 628 629```ts 630import hilog from '@ohos.hilog' 631import testNapi from 'libentry.so' 632 633const err = new Error("a fatal exception occurred"); 634testNapi.fatalException(err); 635``` 636 637以上代码如果要在native cpp中打印日志,需在CMakeLists.txt文件中添加以下配置信息(并添加头文件:#include "hilog/log.h"): 638 639```text 640// CMakeLists.txt 641add_definitions( "-DLOG_DOMAIN=0xd0d0" ) 642add_definitions( "-DLOG_TAG=\"testTag\"" ) 643target_link_libraries(entry PUBLIC libhilog_ndk.z.so) 644```