diff --git a/Services/GotifyApiService.cs b/Services/GotifyApiService.cs index e7b7f44..cf33c96 100644 --- a/Services/GotifyApiService.cs +++ b/Services/GotifyApiService.cs @@ -7,22 +7,55 @@ namespace WindowsGotify.Services; public sealed class GotifyApiService { - private readonly GotifyConfig _config; + private readonly AppConfig _config; private readonly Logger _logger; private readonly HttpClient _httpClient; + private readonly object _httpLock = new(); + private string _appliedBaseUrl = ""; + private string _appliedToken = ""; public GotifyApiService(AppConfig config, Logger logger) { - _config = config.Gotify; + _config = config; _logger = logger; _httpClient = new HttpClient { - BaseAddress = new Uri(_config.Url.TrimEnd('/') + "/"), Timeout = TimeSpan.FromSeconds(15) }; + SyncAuthHeaders(); + } - _httpClient.DefaultRequestHeaders.Authorization = - new AuthenticationHeaderValue("Bearer", _config.ClientToken); + /// + /// 检测 URL/Token 是否变了,变了就刷新 HttpClient 的 Authorization。 + /// 注意:HttpClient.BaseAddress 构造后只读,所以我们用绝对 URI 绕过。 + /// + private void SyncAuthHeaders() + { + var baseUrl = (_config.Gotify.Url ?? "").TrimEnd('/'); + var token = _config.Gotify.ClientToken ?? ""; + + if (_appliedBaseUrl == baseUrl && _appliedToken == token) + return; + + lock (_httpLock) + { + if (_appliedBaseUrl == baseUrl && _appliedToken == token) + return; + + // 显式给默认 header;实际请求走绝对 URI,所以 BaseAddress 永远为空 + _httpClient.DefaultRequestHeaders.Authorization = + string.IsNullOrEmpty(token) ? null : new AuthenticationHeaderValue("Bearer", token); + _appliedBaseUrl = baseUrl; + _appliedToken = token; + } + } + + private Uri BuildUri(string path) + { + var baseUrl = (_config.Gotify.Url ?? "").TrimEnd('/'); + if (string.IsNullOrEmpty(baseUrl)) + throw new InvalidOperationException("Gotify URL 未配置。请在主窗填入 URL 并保存。"); + return new Uri(baseUrl + "/" + path); } /// @@ -30,8 +63,9 @@ public sealed class GotifyApiService /// public async Task> GetMessagesSinceAsync(long sinceId, int limit, CancellationToken ct) { + SyncAuthHeaders(); var path = $"message?limit={Math.Clamp(limit, 1, 100)}&since={Math.Max(0, sinceId)}"; - using var response = await _httpClient.GetAsync(path, ct); + using var response = await _httpClient.GetAsync(BuildUri(path), ct); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(ct); @@ -44,8 +78,9 @@ public sealed class GotifyApiService /// public async Task> GetRecentMessagesAsync(int limit, CancellationToken ct) { + SyncAuthHeaders(); var path = $"message?limit={Math.Clamp(limit, 1, 100)}&since=0"; - using var response = await _httpClient.GetAsync(path, ct); + using var response = await _httpClient.GetAsync(BuildUri(path), ct); response.EnsureSuccessStatusCode(); await using var stream = await response.Content.ReadAsStreamAsync(ct);