Xử lý lỗi
Hệ thống exception và cách xử lý lỗi trong .NET SDK
SDK sử dụng hệ thống exception phân cấp, tất cả kế thừa từ SsiException (và System.Exception).
Danh sách exception
| Exception | Kế thừa | Mô tả |
|---|---|---|
SsiException | Exception | Exception cơ sở. Có Code, StatusCode, ResponseBody, Headers |
AuthenticationException | SsiException | Xác thực thất bại (sai credentials, token hết hạn, lỗi chữ ký) |
SmartOtpPendingException | AuthenticationException | Smart OTP chưa được duyệt (HTTP 202, code 401114), hoặc hết số lần poll mà chưa duyệt |
SmartOtpRejectedException | AuthenticationException | Smart OTP bị từ chối hoặc không hợp lệ (401113, 401115, 401116). Kết thúc, không poll tiếp. |
ReauthenticationRequiredException | AuthenticationException | Token đã hết hạn, không refresh được và không có otp/transactionId mới: cần xác thực lại |
ApiException | SsiException | API trả về lỗi. Có Code, StatusCode, ResponseBody |
DuplicateRequestException | ApiException | Yêu cầu trùng lặp (HTTP 409, code mặc định "409") |
WebSocketException | SsiException | Lỗi kết nối hoặc giao tiếp WebSocket |
TradingWsError | WebSocketException | Trading WebSocket: server từ chối socket hoặc một lệnh. Có Status, ErrorCode, ServerMessage |
ValidationException | SsiException | Lỗi validate input, phát hiện ở client, chưa gửi gì |
RateLimitException | SsiException | Vượt giới hạn request (HTTP 429). Mã mặc định "RATE_LIMITED" |
Chuỗi kế thừa
Exception → SsiException → AuthenticationException → SmartOtpPendingException
→ SmartOtpRejectedException
→ ReauthenticationRequiredException
→ ApiException → DuplicateRequestException
→ WebSocketException → TradingWsError
→ ValidationException
→ RateLimitExceptionThuộc tính exception cơ sở
public class SsiException : Exception
{
public string Code { get; } // mã lỗi của server (ví dụ "401114"), nếu không có thì HTTP status hoặc mã SDK
public int StatusCode { get; }
public Dictionary<string, JsonElement>? ResponseBody { get; } // body đã che thông tin nhạy cảm
public IReadOnlyDictionary<string, string> Headers { get; } // header phản hồi (rate limit, Retry-After...), không gồm Authorization
}RateLimitException bổ sung thêm:
public long? RetryAfterMs { get; } // mili-giây server yêu cầu chờ (Retry-After), nếu có
public int? Limit { get; }
public int? Remaining { get; }
public double? Reset { get; }TradingWsError bổ sung int Status, string ErrorCode, string ServerMessage. Thông báo của nó không bao giờ chứa params đã ký.
Mã lỗi của server: ServerErrorCode và HttpStatus
ServerErrorCode là lớp tĩnh chứa các mã số mà server trả trong trường code (ví dụ PushApprovalPending = 401114, SignatureMissing = 401006, SignatureBodyEmpty = 401008, SignatureMismatch = 401013, ReplayWindowExceeded = 400111, OtpVerificationFailed = 401100, NoScopeGranted = 403100), cùng ServerErrorCode.IsKnown(int code). Danh sách đầy đủ xem trong mã nguồn SDK và Mã lỗi. HttpStatus có các hàm phân loại IsAuthError, IsRateLimit, IsClientError, IsServerError.
Sử dụng cơ bản
using SsiSdk;
try
{
await auth.AuthenticateAsync("YOUR_OTP");
}
catch (SsiException ex)
{
Console.WriteLine($"Lỗi: {ex.Message} (code: {ex.Code})");
}Xử lý chi tiết theo loại lỗi
Kiểm soát đã áp dụng: tài khoản là placeholder,
catchđi từ exception đặc thù đến tổng quát, không retry tự động với lệnh (SDK không gửi lại POST), không inResponseBodyhay token ra log.
using SsiSdk;
try
{
var result = await trading.Trading.PlaceLimitOrderAsync(
"YOUR_ACCOUNT_NO", "SSI", OrderSide.Buy, 100, 68000m);
}
catch (SmartOtpRejectedException)
{
Console.WriteLine("Smart OTP bị từ chối, cần yêu cầu OTP mới");
}
catch (SmartOtpPendingException)
{
Console.WriteLine("Smart OTP chưa được duyệt");
}
catch (ReauthenticationRequiredException)
{
Console.WriteLine("Token hết hạn, cần xác thực lại");
}
catch (AuthenticationException)
{
Console.WriteLine("Cần xác thực lại");
}
catch (RateLimitException ex)
{
Console.WriteLine($"Rate limited, retry sau {ex.RetryAfterMs} ms");
}
catch (DuplicateRequestException ex)
{
// Phải catch trước ApiException
Console.WriteLine($"Yêu cầu trùng lặp (409): {ex.Message}");
}
catch (ApiException ex)
{
Console.WriteLine($"API error {ex.StatusCode}: {ex.Message}");
}
catch (ValidationException ex)
{
Console.WriteLine($"Validation: {ex.Message}");
}
catch (TradingWsError ex)
{
Console.WriteLine($"Trading WS bị từ chối: {ex.Status} {ex.ErrorCode}");
}
catch (WebSocketException ex)
{
Console.WriteLine($"WebSocket: {ex.Message}");
}
catch (SsiException ex)
{
Console.WriteLine($"SDK error: {ex.Message}");
}Ví dụ trên gộp cả lỗi REST và WebSocket để liệt kê thứ tự catch; trong thực tế một lời gọi chỉ ném một số loại trong đó (TradingWsError chỉ đến từ Trading WebSocket).
Gợi ý xử lý
- Bắt exception cụ thể trước,
SsiExceptionsau cùng làm fallback (theo thứ tựcatchtừ đặc thù đến tổng quát).SmartOtp*/ReauthenticationRequiredExceptionphải đứng trướcAuthenticationException,DuplicateRequestExceptiontrướcApiException,TradingWsErrortrướcWebSocketException. - Bắt
AuthenticationExceptionkhi cần refresh token hoặc yêu cầu OTP mới. Với Smart OTP,SmartOtpPendingExceptionnghĩa là chưa duyệt (có thể thử lại), cònSmartOtpRejectedExceptionlà kết thúc: xin OTP mới. - Bắt
RateLimitExceptionvà tôn trọngRetryAfterMs(mili-giây) để backoff. SDK chỉ tự chờ 429 với GET; POST/PUT/DELETE không bao giờ được gửi lại. - Bắt
ApiExceptionđể xử lý lỗi nghiệp vụ từ server (Code,StatusCode,ResponseBody). - Bắt
WebSocketExceptionkhi xử lý streaming. Sau timeout của một lệnh, kết quả là không xác định: kiểm tra sổ lệnh trước khi gửi lại. - Bắt
ValidationExceptionkhi input không hợp lệ trước khi gọi API (SDK tự validate ở client; không có request nào được gửi).