You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Asp.net Core接收Shopify Webhook时请求读取异常及超时问题

解决Asp.net接收Shopify Webhook时的Request.Form异常与Body读取超时问题

错误原因分析

  1. System.InvalidOperationException访问Request.Form时抛出:
    Shopify Webhook默认以application/json格式发送请求,而非表单格式(application/x-www-form-urlencoded)。此时尝试读取Request.Form,Asp.net会尝试将JSON格式的请求体解析为表单数据,格式不匹配直接抛出异常。

  2. 读取Request.Body超时:

    • Request.Body是只读流,默认只能读取一次,若之前有中间件或绑定逻辑已读取过流,未重置Position会导致后续读取阻塞超时。
    • 同步读取流(如ReadToEnd())易引发线程阻塞,导致超时。

解决方案

方案1:直接用[FromBody]绑定模型(推荐)

利用Asp.net的自动模型绑定,直接将JSON请求体绑定到自定义模型,无需手动读取流:

// 定义对应Shopify Webhook的模型(示例以订单创建Webhook为例)
public class ShopifyOrderWebhook
{
    public long Id { get; set; }
    public string Email { get; set; }
    // 其他字段根据Shopify Webhook文档补充
}

[HttpPost("shopify/webhook/order-created")]
public async Task<IActionResult> OrderCreated([FromBody] ShopifyOrderWebhook webhookData)
{
    // 处理Webhook业务逻辑
    // 务必验证HMAC签名(见下方补充)
    
    return Ok();
}

方案2:手动异步读取Request.Body

若需直接处理原始请求体内容,使用异步方式读取并确保流位置正确:

[HttpPost("shopify/webhook")]
public async Task<IActionResult> HandleWebhook()
{
    // 重置流位置到开头(避免之前的读取操作导致流指针在末尾)
    Request.Body.Position = 0;
    
    // 异步读取请求体
    using var streamReader = new StreamReader(Request.Body);
    var rawBody = await streamReader.ReadToEndAsync();
    
    // 解析JSON(可使用System.Text.Json或Newtonsoft.Json)
    var webhookData = JsonSerializer.Deserialize<YourWebhookModel>(rawBody);
    
    // 处理逻辑 + HMAC验证
    
    return Ok();
}

补充:启用Request.Body可重复读取(可选)

如果需要多次读取请求体(比如先验证签名再解析模型),需在配置中开启流缓冲:
在Program.cs中添加:

builder.Services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(options =>
{
    options.BufferBody = true;
    options.BufferBodyLengthLimit = 10 * 1024 * 1024; // 10MB,根据Shopify Webhook大小调整
});

关键:验证Shopify Webhook签名

无论哪种方案,都必须验证请求头中的X-Shopify-Hmac-SHA256签名,确保请求合法:

private bool ValidateShopifyHmac(string rawBody, string hmacHeader, string shopifySecret)
{
    var secretBytes = Encoding.UTF8.GetBytes(shopifySecret);
    var bodyBytes = Encoding.UTF8.GetBytes(rawBody);
    var hmac = new HMACSHA256(secretBytes);
    var computedHmac = Convert.ToBase64String(hmac.ComputeHash(bodyBytes));
    
    return computedHmac.Equals(hmacHeader, StringComparison.OrdinalIgnoreCase);
}

内容的提问来源于stack exchange,提问作者Jed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:45:31