wake-ios/wake/Utils/NetworkService.swift
2025-08-21 19:39:05 +08:00

208 lines
7.1 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import Foundation
enum NetworkError: Error {
case invalidURL
case noData
case decodingError(Error)
case serverError(String)
case unauthorized
case other(Error)
case networkError(Error)
case unknownError(Error)
var localizedDescription: String {
switch self {
case .invalidURL:
return "无效的URL"
case .noData:
return "没有收到数据"
case .decodingError(let error):
return "数据解析错误: \(error.localizedDescription)"
case .serverError(let message):
return "服务器错误: \(message)"
case .unauthorized:
return "未授权,请重新登录"
case .other(let error):
return error.localizedDescription
case .networkError(let error):
return "网络请求错误: \(error.localizedDescription)"
case .unknownError(let error):
return "未知错误: \(error.localizedDescription)"
}
}
}
class NetworkService {
static let shared = NetworkService()
//
private let defaultHeaders: [String: String] = [
"Content-Type": "application/json",
"Accept": "application/json"
]
private init() {}
// MARK: -
private func request<T: Decodable>(
_ method: String,
path: String,
parameters: [String: Any]? = nil,
headers: [String: String]? = nil,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
// URL
guard let url = URL(string: APIConfig.baseURL + path) else {
completion(.failure(.invalidURL))
return
}
//
var request = URLRequest(url: url)
request.httpMethod = method
// -
defaultHeaders.forEach { key, value in
request.setValue(value, forHTTPHeaderField: key)
}
//
APIConfig.authHeaders.forEach { key, value in
request.setValue(value, forHTTPHeaderField: key)
}
//
headers?.forEach { key, value in
request.setValue(value, forHTTPHeaderField: key)
}
// POST/PUT
if let parameters = parameters, (method == "POST" || method == "PUT") {
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
} catch {
completion(.failure(.other(error)))
return
}
}
//
print("🌐 [Network] \(method) \(url.absoluteString)")
if let headers = request.allHTTPHeaderFields {
print("📤 Headers: \(headers)")
}
if let body = request.httpBody, let bodyString = String(data: body, encoding: .utf8) {
print("📦 Body: \(bodyString)")
}
//
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
//
self?.handleResponse(data: data, response: response, error: error, completion: completion)
}
//
task.resume()
}
private func handleResponse<T: Decodable>(
data: Data?,
response: URLResponse?,
error: Error?,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
//
if let httpResponse = response as? HTTPURLResponse {
print("📥 [Network] Status: \(httpResponse.statusCode) \(HTTPURLResponse.localizedString(forStatusCode: httpResponse.statusCode))")
if let headers = httpResponse.allHeaderFields as? [String: Any] {
print("📥 Headers: \(headers)")
}
//
if !(200...299).contains(httpResponse.statusCode) {
print("❌ [Network] 请求失败,状态码: \(httpResponse.statusCode)")
if let data = data, let errorResponse = String(data: data, encoding: .utf8) {
print("❌ [Network] 错误响应: \(errorResponse)")
}
}
}
//
if let error = error {
print("❌ [Network] 网络请求错误: \(error.localizedDescription)")
completion(.failure(.networkError(error)))
return
}
//
guard let data = data else {
print("❌ [Network] 没有收到数据")
completion(.failure(.noData))
return
}
//
if let responseString = String(data: data, encoding: .utf8) {
print("📥 [Network] 响应数据: \(responseString)")
}
do {
// JSON
let decoder = JSONDecoder()
let result = try decoder.decode(T.self, from: data)
completion(.success(result))
} catch let decodingError as DecodingError {
print("❌ [Network] JSON解析失败: \(decodingError.localizedDescription)")
if let dataString = String(data: data, encoding: .utf8) {
print("📋 [Network] 原始响应: \(dataString)")
}
completion(.failure(.decodingError(decodingError)))
} catch {
print("❌ [Network] 未知错误: \(error.localizedDescription)")
completion(.failure(.unknownError(error)))
}
}
// MARK: -
/// GET
func get<T: Decodable>(
path: String,
parameters: [String: Any]? = nil,
headers: [String: String]? = nil,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
request("GET", path: path, parameters: parameters, headers: headers, completion: completion)
}
/// POST
func post<T: Decodable>(
path: String,
parameters: [String: Any]? = nil,
headers: [String: String]? = nil,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
request("POST", path: path, parameters: parameters, headers: headers, completion: completion)
}
/// DELETE
func delete<T: Decodable>(
path: String,
parameters: [String: Any]? = nil,
headers: [String: String]? = nil,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
request("DELETE", path: path, parameters: parameters, headers: headers, completion: completion)
}
/// PUT
func put<T: Decodable>(
path: String,
parameters: [String: Any]? = nil,
headers: [String: String]? = nil,
completion: @escaping (Result<T, NetworkError>) -> Void
) {
request("PUT", path: path, parameters: parameters, headers: headers, completion: completion)
}
}