关于.NET Core C#中RevenueCat Webhook返回400 BadRequest且无法获取JSON响应的技术求助
Alright, let's figure out why you're getting that 400 Bad Request and fix your RevenueCat Webhook implementation in .NET Core. I'll walk through the common pitfalls and share a complete, tested example that should resolve this issue.
Common Issues Causing the 400 Error
- Incorrect Signature Validation: Your current code compares the
Authorizationheader directly to your webhook secret, which isn't how RevenueCat's verification works. RevenueCat uses an HMAC-SHA256 signature of the request body (sent in theX-RevenueCat-Signatureheader), not a direct secret match inAuthorization. - Request Body Reading Problems:
HttpContext.Request.Bodyis a forward-only stream. If any middleware reads it before your code, you'll get an empty string when you try to read it, leading to unexpected errors that trigger a 400. - Improper Response Handling: RevenueCat expects a
200 OKresponse to confirm receipt. If your code throws exceptions without proper handling, it might return a 400/500 instead of the required success status.
Fixed Implementation Example
First, add a helper class to handle HMAC signature validation correctly:
using System.Security.Cryptography; using System.Text; public static class RevenueCatWebhookValidator { public static bool IsValidSignature(string requestBody, string webhookSecret, string signatureHeader) { using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(webhookSecret)); var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(requestBody)); var computedSignature = Convert.ToHexString(computedHash).ToLowerInvariant(); // RevenueCat's signature uses lowercase hex—compare case-insensitively to avoid mismatches return computedSignature.Equals(signatureHeader.ToLowerInvariant()); } }
Then update your controller endpoint to handle requests safely:
[ApiController] [Route("api/revenuecat/webhook")] public class RevenueCatWebhookController : ControllerBase { private readonly IConfiguration _config; private readonly ILogger<RevenueCatWebhookController> _logger; public RevenueCatWebhookController(IConfiguration config, ILogger<RevenueCatWebhookController> logger) { _config = config; _logger = logger; } [HttpPost] public async Task<IActionResult> ProcessWebhook() { var webhookSecret = _config[Constants.RevenueCatWebHookSecret]; if (string.IsNullOrWhiteSpace(webhookSecret)) { _logger.LogError("RevenueCat webhook secret is missing from configuration."); return StatusCode(StatusCodes.Status500InternalServerError); } // Copy request body to memory stream to avoid issues with forward-only streams string requestBody; using (var memoryStream = new MemoryStream()) { await Request.Body.CopyToAsync(memoryStream); memoryStream.Position = 0; requestBody = await new StreamReader(memoryStream).ReadToEndAsync(); } // Retrieve the correct signature header from RevenueCat var signature = Request.Headers["X-RevenueCat-Signature"].FirstOrDefault(); if (string.IsNullOrWhiteSpace(signature)) { _logger.LogWarning("Received RevenueCat webhook without X-RevenueCat-Signature header."); return Unauthorized(); } // Validate the signature before processing the payload if (!RevenueCatWebhookValidator.IsValidSignature(requestBody, webhookSecret, signature)) { _logger.LogWarning("Invalid signature on RevenueCat webhook request."); return Unauthorized(); } // Process the payload (add your business logic here) _logger.LogInformation("Received valid RevenueCat webhook payload: {Payload}", requestBody); // Example: Deserialize the payload (define your own model classes for RevenueCat events) // var webhookEvent = System.Text.Json.JsonSerializer.Deserialize<RevenueCatWebhookEvent>(requestBody); // Always return 200 OK to confirm receipt—RevenueCat will retry on non-200 responses return Ok(); } }
Key Tips to Avoid Future Issues
- Use the Correct Header: RevenueCat sends signatures in
X-RevenueCat-Signature, notAuthorization. Your original code checked the wrong header, which would reject all valid requests. - Read the Body Safely: Copying to a
MemoryStreamensures you can access the payload even if other middleware has interacted with the request stream. - Return 200 OK: This is required for RevenueCat to mark the webhook as successfully delivered. Failing to do so will trigger retries and show errors in their dashboard.
- Exception Handling: Ensure your global exception handler correctly maps errors to HTTP status codes. If your
APIExceptionisn't handled properly, it might return a 400 instead of a 401 for unauthorized requests.
内容的提问来源于stack exchange,提问作者Rahul Verma
相关产品推荐
相关产品推荐

