diff --git a/src/SimpleAdmin.Api.IntegrationTests/WeChatRouteIntegrationTests.cs b/src/SimpleAdmin.Api.IntegrationTests/WeChatRouteIntegrationTests.cs index 205ac8b..2564cf3 100644 --- a/src/SimpleAdmin.Api.IntegrationTests/WeChatRouteIntegrationTests.cs +++ b/src/SimpleAdmin.Api.IntegrationTests/WeChatRouteIntegrationTests.cs @@ -46,6 +46,17 @@ public class WeChatRouteIntegrationTests (await response.Content.ReadAsStringAsync()).Should().Be(echostr); } + [Fact] + public async Task WeChatValidateLegacy_Head_ShouldReturn200() + { + await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: ConfigureWeChatFallback); + + var request = new HttpRequestMessage(HttpMethod.Head, "/apiwechat/verification"); + var response = await host.Client.SendAsync(request); + + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + private static void ConfigureWeChatFallback(IServiceCollection services) { services.PostConfigure(options => diff --git a/src/SimpleAdmin.Api/Auth/AuthService.WeChatMp.cs b/src/SimpleAdmin.Api/Auth/AuthService.WeChatMp.cs index df57e47..91b67f0 100644 --- a/src/SimpleAdmin.Api/Auth/AuthService.WeChatMp.cs +++ b/src/SimpleAdmin.Api/Auth/AuthService.WeChatMp.cs @@ -27,6 +27,7 @@ public partial class AuthService /// [AllowAnonymous] [HttpGet("/apiwechat/verification")] + [HttpHead("/apiwechat/verification")] [Produces("text/plain")] [ApiExplorerSettings(GroupName = "WeChat")] public async Task WeChatValidateLegacyAsync( @@ -36,8 +37,34 @@ public partial class AuthService [FromQuery] string? echostr, CancellationToken cancellationToken = default) { - var options = await WeChatMpConfigProvider.GetAsync(cancellationToken); - return WeChatMpCallbackSupport.Validate(options, signature, timestamp, nonce, echostr); + if (string.Equals( + httpContextAccessor.HttpContext?.Request.Method, + HttpMethods.Head, + StringComparison.OrdinalIgnoreCase)) + { + return WeChatMpCallbackSupport.HeadOk(); + } + + return await WeChatValidateCoreAsync(signature, timestamp, nonce, echostr, cancellationToken); + } + + private async Task WeChatValidateCoreAsync( + string? signature, + string? timestamp, + string? nonce, + string? echostr, + CancellationToken cancellationToken) + { + try + { + var options = await WeChatMpConfigProvider.GetAsync(cancellationToken); + return WeChatMpCallbackSupport.Validate(options, signature, timestamp, nonce, echostr); + } + catch (Exception ex) + { + WeChatLogger.LogWarning(ex, "微信公众号验签读取配置失败"); + return WeChatMpCallbackSupport.PlainError(); + } } /// diff --git a/src/SimpleAdmin.Api/WeChat/WeChatMpCallbackSupport.cs b/src/SimpleAdmin.Api/WeChat/WeChatMpCallbackSupport.cs index 4d3d126..d5ecbc2 100644 --- a/src/SimpleAdmin.Api/WeChat/WeChatMpCallbackSupport.cs +++ b/src/SimpleAdmin.Api/WeChat/WeChatMpCallbackSupport.cs @@ -17,7 +17,7 @@ internal static class WeChatMpCallbackSupport // 微信服务器要求 HTTP 200 + 纯文本 echostr,不可抛 BusinessException(会变成 JSON 非 200) if (string.IsNullOrWhiteSpace(options.Token)) { - return PlainText("error"); + return PlainError(); } if (string.IsNullOrWhiteSpace(signature) @@ -25,13 +25,19 @@ internal static class WeChatMpCallbackSupport || string.IsNullOrWhiteSpace(nonce) || string.IsNullOrWhiteSpace(echostr)) { - return PlainText("error"); + return PlainError(); } var valid = WeChatSignatureHelper.Validate(options.Token, timestamp, nonce, signature); return PlainText(valid ? echostr : "error"); } + /// 微信或探活可能发 HEAD,须返回 200(WMS/Spring 默认支持)。 + public static ContentResult HeadOk() => + new() { Content = string.Empty, ContentType = "text/plain; charset=utf-8", StatusCode = StatusCodes.Status200OK }; + + public static ContentResult PlainError() => PlainText("error"); + public static async Task HandleMessageAsync( WeChatMpOptions options, IWeChatEventHandler eventHandler,