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);