# 错误处理

> Handle errors in your modules using error codes and custom error-handling logic.

了解如何处理模块中的错误。

## 错误代码##error-codes

如果模块抛出异常，Cloud Code 将返回 `422` 状态错误。

对于错误处理逻辑，请使用从 Cloud Code API 错误响应返回的错误代码或错误类型，而不是错误消息。错误消息将来可能会更改，但错误代码和类型会保持不变。

## 对错误进行包装##error-wrapping

请将代码包装在 `try`/`catch` 代码块中来处理错误。如果发生错误，您可以记录该错误并向客户端返回一个错误。

例如，您可以编写一个未包装的函数：

```csharp
    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,  ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));
    }
```

这个未包装的函数返回一般错误：

```json
{
  "type": "problems/invocation",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "Invocation Error",
  "instance": null,
  "code": 9009,
  "details": [
    {
      "message": "Error executing Cloud Code function. Exception type: ApiException. Message: Bad Request",
      "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
      "stackTrace": [
        "at Unity.Services.CloudCode.Shared.HttpApiClient.ToApiResponse[T](HttpResponseMessage response)",
        "at Unity.Services.CloudCode.Shared.HttpApiClient.SendAsync[T](String path, HttpMethod method, ApiRequestOptions options, IApiConfiguration configuration, CancellationToken cancellationToken)",
        "at Unity.Services.Economy.Api.EconomyCurrenciesApi.IncrementPlayerCurrencyBalanceAsync(IExecutionContext executionContext, String accessToken, String projectId, String playerId, String currencyId, CurrencyModifyBalanceRequest currencyModifyBalanceRequest, String configAssignmentHash, String unityInstallationId, String analyticsUserId, CancellationToken cancellationToken)",
        "at Sample.HelloWorld.IncrementBalanceUnhandled(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 148"
      ]
    }
  ]
}
```

如果添加 `try`/`catch` 代码块来处理错误，则可以返回更具体的错误消息。您还可以记录错误：

```csharp
    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
            return await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

        }
        catch (ApiException e)
        {
             _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }
```

以下已包装的函数返回一条包含更多详细信息的错误消息：

```json
{
    "type": "problems/invocation",
    "title": "Unprocessable Entity",
    "status": 422,
    "detail": "Invocation Error",
    "instance": null,
    "code": 9009,
    "details": [
        {
            "message": "Error executing Cloud Code function. Exception type: Exception. Message: Failed to increment balance for playerId 7wCG6G0d1PU6WSVZPG9oQ1op97xd. Error: Bad Request",
            "name": "ScriptRunner.Exceptions.CloudCodeRuntimeException",
            "stackTrace": [
                "at Sample.HelloWorld.IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, String currencyId) in Sample/Main/HelloWorld.cs:line 165"
            ]
        }
    ]
}
```

您可以在 [Unity Dashboard](https://cloud.unity.com) 中查看日志。要获取更多有关该错误的详细信息，请选择 **Products（产品）**> **Cloud Code** > **Logs（日志）**。

## 批处理请求的错误处理##error-handling-with-batch-requests

如需了解有关批处理请求的更多信息，请参阅[批处理请求](./batch-requests.md)。

## 状态代码##status-codes

每当 Cloud Code C# SDK 返回不成功的状态代码时，该 SDK 都会抛出 `ApiException` 异常。您可以使用此异常来获取状态代码和错误消息。

您可以捕获 `ApiException` 异常并对其进行处理，或者记录并重新抛出该错误。这意味着您不必检查 `ApiResponse` 对象中的状态代码。

## 未处理的错误##unhandled-errors

Cloud Code 无法处理因内存泄漏导致的异常，例如无限循环。如果您的模块超出了内存限制，工作线程最终会崩溃。Cloud Code 无法处理 `async void` 模式的异常。始终返回 `Task` 或 `Task<T>`。要了解有关异步编程的最佳做法，请参阅官方 [Microsoft 文档](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming)。

## Logging##logging

为了帮助您调试模块，您可以使用 `ILogger` 接口记录错误和警告。

Cloud Code 会自动将 `playerId`、`environmentId` 和 `projectId` 等属性添加到日志中，因此您无需将它们添加到日志消息中。

```csharp
public class HelloWorld
{
    private readonly ILogger<HelloWorld> _logger;
    public HelloWorld(ILogger<HelloWorld> logger)
    {
        _logger = logger;
    }

    [CloudCodeFunction("IncrementBalance")]
    public async  Task<ApiResponse<CurrencyBalanceResponse>> IncrementPlayerBalance(IGameApiClient gameApiClient, IExecutionContext ctx, string currencyId)
    {
        try
        {
           var res =  await gameApiClient.EconomyCurrencies.IncrementPlayerCurrencyBalanceAsync(ctx, ctx.ServiceToken,
                ctx.ProjectId, ctx.PlayerId, currencyId, new CurrencyModifyBalanceRequest(currencyId, 10));

           _logger.LogInformation("Incremented currency {currencyId} balance by {amount}", currencyId, 10);
           return res;

        }
        catch (ApiException e)
        {
            _logger.LogError("Failed to increment {currencyId} balance for the player. Error: {error}", currencyId, e.Message);
            throw new Exception($"Failed to increment balance for playerId {ctx.PlayerId}. Error: {e.Message}");
        }
    }

    public class ModuleConfig : ICloudCodeSetup
    {
        public void Setup(ICloudCodeConfig config)
        {
            config.Dependencies.AddSingleton(GameApiClient.Create());
        }
    }
}
```

您可以记录不同级别的消息。这些级别可以帮助您在 Unity Dashboard 中查询日志。

```csharp
    _logger.LogDebug("debug message");
    _logger.LogInformation("info message");
    _logger.LogWarning("warning message");
    _logger.LogError("error message");
    _logger.LogCritical("critical message");
```

要查看和过滤日志，请导航到 [Unity Dashboard](https://cloud.unity.com) 并选择 **Products（产品）** > **Cloud Code** > **Logs（日志）**。

如需了解更多信息，请参阅[发出日志](../../logging/tutorials/emit-logs#cloud-code-c-modules)。
