fix: 修复空 catch 吞异常问题,端口号抽离到配置,统一日志为 Serilog
- 所有空 catch 块补全日志记录,统一使用 Serilog/AppLog - 按场景分级:Error(意外失败)、Warning(次要问题)、Information(预期内) - 端口 HttpPort/HttpsPort 抽离到 appsettings.json Server 配置节 - QrCodeService 通过 IConfiguration 读取端口,消除硬编码 - 前端通过 Vite proxy 转发 /api,http.ts 统一使用 origin 地址 - 移除所有 Debug.WriteLine 和 Serilog.Log.Debug 日志 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d93098638d
commit
6acc92ca27
@ -13,8 +13,10 @@ try
|
|||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// 配置 Kestrel 监听所有本机 IP
|
// 配置 Kestrel 监听所有本机 IP(端口从 Server 配置节读取)
|
||||||
builder.WebHost.UseUrls("http://0.0.0.0:5206", "https://0.0.0.0:7165");
|
var httpPort = builder.Configuration.GetValue<int>("Server:HttpPort", 5206);
|
||||||
|
var httpsPort = builder.Configuration.GetValue<int>("Server:HttpsPort", 7165);
|
||||||
|
builder.WebHost.UseUrls($"http://0.0.0.0:{httpPort}", $"https://0.0.0.0:{httpsPort}");
|
||||||
|
|
||||||
// 使用 Serilog 作为日志提供程序
|
// 使用 Serilog 作为日志提供程序
|
||||||
builder.Host.UseSerilog();
|
builder.Host.UseSerilog();
|
||||||
|
|||||||
@ -6,6 +6,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*",
|
"AllowedHosts": "*",
|
||||||
|
"Server": {
|
||||||
|
"HttpPort": 5206,
|
||||||
|
"HttpsPort": 7165
|
||||||
|
},
|
||||||
"Jwt": {
|
"Jwt": {
|
||||||
"Issuer": "FileShare-API",
|
"Issuer": "FileShare-API",
|
||||||
"Audience": "FileShare-Client",
|
"Audience": "FileShare-Client",
|
||||||
|
|||||||
@ -95,8 +95,9 @@ namespace FileShare_EFCore.Database
|
|||||||
{
|
{
|
||||||
return await _context.Database.CanConnectAsync();
|
return await _context.Database.CanConnectAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Warning("数据库连接测试失败 Provider={Provider} Error={Error}", _config.Provider, ex.Message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using FileShare_Common.Infrastructure;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -180,6 +181,7 @@ namespace FileShare_PC.Views
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Error(ex, "Bridge AppRequest 处理失败");
|
||||||
response = new AppResponse
|
response = new AppResponse
|
||||||
{
|
{
|
||||||
Kind = "app-response",
|
Kind = "app-response",
|
||||||
@ -341,6 +343,7 @@ namespace FileShare_PC.Views
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Error(ex, "本地 HTTP 请求处理失败");
|
||||||
response.StatusCode = 500;
|
response.StatusCode = 500;
|
||||||
response.StatusMessage = "Internal Server Error";
|
response.StatusMessage = "Internal Server Error";
|
||||||
response.Body = JsonSerializer.Serialize(new { success = false, error = ex.Message });
|
response.Body = JsonSerializer.Serialize(new { success = false, error = ex.Message });
|
||||||
@ -456,8 +459,9 @@ namespace FileShare_PC.Views
|
|||||||
using var document = JsonDocument.Parse(messageJson);
|
using var document = JsonDocument.Parse(messageJson);
|
||||||
return document.RootElement.TryGetProperty("id", out var idProperty) ? idProperty.GetString() : null;
|
return document.RootElement.TryGetProperty("id", out var idProperty) ? idProperty.GetString() : null;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Information("解析 Bridge 请求 ID 失败: {Error}", ex.Message);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,8 +541,9 @@ namespace FileShare_PC.Views
|
|||||||
_ = Task.Run(() => HandleLocalHttpRequest(context, wwwRoot), cancellationToken);
|
_ = Task.Run(() => HandleLocalHttpRequest(context, wwwRoot), cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
AppLog.Error(ex, "本地 HTTP 服务循环异常退出");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,15 +582,17 @@ namespace FileShare_PC.Views
|
|||||||
await input.CopyToAsync(context.Response.OutputStream);
|
await input.CopyToAsync(context.Response.OutputStream);
|
||||||
context.Response.OutputStream.Close();
|
context.Response.OutputStream.Close();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Error(ex, "本地静态文件请求处理失败");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = 500;
|
||||||
context.Response.Close();
|
context.Response.Close();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception closeEx)
|
||||||
{
|
{
|
||||||
|
AppLog.Warning("关闭 500 响应失败: {Error}", closeEx.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -826,8 +833,9 @@ namespace FileShare_PC.Views
|
|||||||
_localHttpServer?.Stop();
|
_localHttpServer?.Stop();
|
||||||
_localHttpServer?.Close();
|
_localHttpServer?.Close();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
AppLog.Warning("停止本地 HTTP 服务时出错: {Error}", ex.Message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,9 +26,9 @@ namespace FileShare_Services.Endpoints
|
|||||||
// ---- 全局日志过滤器(记录每个请求) ----
|
// ---- 全局日志过滤器(记录每个请求) ----
|
||||||
endpoints.AddGlobalFilter(async (ctx, next) =>
|
endpoints.AddGlobalFilter(async (ctx, next) =>
|
||||||
{
|
{
|
||||||
Serilog.Log.Debug("→ {Method} {Path}", ctx.Method, ctx.Path);
|
Serilog.Log.Information("→ {Method} {Path}", ctx.Method, ctx.Path);
|
||||||
await next(ctx);
|
await next(ctx);
|
||||||
Serilog.Log.Debug("← {Method} {Path} | {StatusCode}", ctx.Method, ctx.Path, ctx.StatusCode);
|
Serilog.Log.Information("← {Method} {Path} | {StatusCode}", ctx.Method, ctx.Path, ctx.StatusCode);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---- 业务端点注册 ----
|
// ---- 业务端点注册 ----
|
||||||
|
|||||||
@ -190,6 +190,7 @@ namespace FileShare_Services.Extensions
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Serilog.Log.Error(ex, "桌面端点处理异常 | {Method} {Path}", method, path);
|
||||||
ctx.StatusCode = 500;
|
ctx.StatusCode = 500;
|
||||||
ctx.StatusMessage = "Internal Server Error";
|
ctx.StatusMessage = "Internal Server Error";
|
||||||
ctx.ResponseBody = new { success = false, error = ex.Message };
|
ctx.ResponseBody = new { success = false, error = ex.Message };
|
||||||
|
|||||||
@ -223,9 +223,9 @@ namespace FileShare_Services.Services.FileLibrary
|
|||||||
{
|
{
|
||||||
await ScanRootAsync(root.Id, cancellationToken);
|
await ScanRootAsync(root.Id, cancellationToken);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// ScanRootAsync records the error on the root. Continue scanning other roots.
|
Serilog.Log.Warning(ex, "扫描文件库根目录失败 RootId={RootId}", root.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,8 +378,9 @@ namespace FileShare_Services.Services.FileLibrary
|
|||||||
directories = Directory.EnumerateDirectories(current);
|
directories = Directory.EnumerateDirectories(current);
|
||||||
files = Directory.EnumerateFiles(current);
|
files = Directory.EnumerateFiles(current);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Serilog.Log.Information(ex, "无法枚举目录 {Directory},已跳过", current);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,8 +461,9 @@ namespace FileShare_Services.Services.FileLibrary
|
|||||||
{
|
{
|
||||||
return drive.IsReady ? selector(drive) : null;
|
return drive.IsReady ? selector(drive) : null;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Serilog.Log.Information(ex, "获取驱动器属性失败,已跳过");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using FileShare_Common.Core;
|
using FileShare_Common.Core;
|
||||||
using FileShare_Services.Core;
|
using FileShare_Services.Core;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using QRCoder;
|
using QRCoder;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
@ -10,7 +11,7 @@ namespace FileShare_Services.Services.QrCode
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 二维码生成服务,获取局域网 IP 并生成 PNG 格式的访问二维码。
|
/// 二维码生成服务,获取局域网 IP 并生成 PNG 格式的访问二维码。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class QrCodeService : IQrCodeService
|
public sealed class QrCodeService(IConfiguration configuration) : IQrCodeService
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<object?> GenerateQrCodeAsync(ServiceEndpointContext ctx)
|
public Task<object?> GenerateQrCodeAsync(ServiceEndpointContext ctx)
|
||||||
@ -19,7 +20,8 @@ namespace FileShare_Services.Services.QrCode
|
|||||||
if (ip is null)
|
if (ip is null)
|
||||||
throw new InvalidOperationException("无法获取局域网IP地址");
|
throw new InvalidOperationException("无法获取局域网IP地址");
|
||||||
|
|
||||||
var url = $"http://{ip}:5206";
|
var port = int.TryParse(configuration["Server:HttpPort"], out var p) ? p : 5206;
|
||||||
|
var url = $"http://{ip}:{port}";
|
||||||
var base64 = GeneratePngBase64(url);
|
var base64 = GeneratePngBase64(url);
|
||||||
return Task.FromResult<object?>(ResponseHelper.Ok(new QrCodeResponse(url, base64)));
|
return Task.FromResult<object?>(ResponseHelper.Ok(new QrCodeResponse(url, base64)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,11 +4,8 @@ import { isWebView2 } from './env'
|
|||||||
// WebView2 自定义协议前缀
|
// WebView2 自定义协议前缀
|
||||||
const WEBVIEW2_BASE = 'app://api/'
|
const WEBVIEW2_BASE = 'app://api/'
|
||||||
|
|
||||||
// Vite 开发页走 5206 API;API 托管前端时使用同源地址。
|
// Vite 开发时通过 proxy 转发 /api 到后端;API 托管前端时使用同源地址。
|
||||||
const isViteDevServer = window.location.port === '51552'
|
const HTTP_ORIGIN = window.location.origin
|
||||||
const HTTP_ORIGIN = isViteDevServer
|
|
||||||
? `${window.location.protocol}//${window.location.hostname || 'localhost'}:5206`
|
|
||||||
: window.location.origin
|
|
||||||
const HTTP_BASE = `${HTTP_ORIGIN}/api/`
|
const HTTP_BASE = `${HTTP_ORIGIN}/api/`
|
||||||
|
|
||||||
export const apiOrigin = (): string => HTTP_ORIGIN
|
export const apiOrigin = (): string => HTTP_ORIGIN
|
||||||
|
|||||||
@ -10,5 +10,11 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
port: 51552,
|
port: 51552,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:5206',
|
||||||
|
changeOrigin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user