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