• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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], &dividend);
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```