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

如何通过Azure APIM以multipart/form-data格式上传大文件至Azure Blob存储?

解决Azure APIM解析multipart/form-data上传大文件到Blob Storage的问题

由于Azure APIM原生不支持context.Request.File来处理multipart/form-data格式的文件上传,我们可以通过手动解析请求体的方式提取文件内容,再转发到Azure Blob Storage。以下是完整的策略代码:

<policies>
    <inbound>
        <base />
        <!-- 仅在请求为multipart/form-data时执行解析逻辑 -->
        <choose>
            <when condition="@(context.Request.Headers.GetValueOrDefault("Content-Type", "").StartsWith("multipart/form-data"))">
                <!-- 1. 获取multipart边界 -->
                <set-variable name="boundary" value="@(context.Request.Headers.GetValueOrDefault("Content-Type", "").Split(';').FirstOrDefault(s => s.Trim().StartsWith("boundary="))?.Split('=')[1].Trim())" />
                <!-- 2. 读取请求体并解析出文件内容 -->
                <set-body>@{
                    var body = context.Request.Body.As<string>(true);
                    if (string.IsNullOrEmpty(body) || string.IsNullOrEmpty((string)context.Variables["boundary"]))
                    {
                        return body;
                    }
                    var boundary = "--" + (string)context.Variables["boundary"];
                    var parts = body.Split(new[] { boundary }, StringSplitOptions.RemoveEmptyEntries);
                    // 找到包含文件的部分(假设只有一个文件字段)
                    var filePart = parts.FirstOrDefault(p => p.Contains("filename="));
                    if (filePart == null)
                    {
                        return body;
                    }
                    // 提取文件内容:跳过头部,直到空行后的内容
                    var contentStart = filePart.IndexOf("\r\n\r\n") + 4;
                    var contentEnd = filePart.LastIndexOf("\r\n--");
                    if (contentStart < 0 || contentEnd < 0)
                    {
                        return body;
                    }
                    var fileContent = filePart.Substring(contentStart, contentEnd - contentStart);
                    // 从文件部分提取文件名(可选,也可以继续用Query参数)
                    var fileNameMatch = System.Text.RegularExpressions.Regex.Match(filePart, @"filename=""(.*?)""");
                    if (fileNameMatch.Success)
                    {
                        context.Variables["fileName"] = fileNameMatch.Groups[1].Value;
                    }
                    return fileContent;
                }</set-body>
                <!-- 3. 修改请求头,适配Blob Storage的PUT要求 -->
                <set-header name="Content-Type" exists-action="override">
                    <value>application/octet-stream</value>
                </set-header>
                <!-- 4. 如果从multipart中提取了文件名,重写URI -->
                <rewrite-uri template="@(
                    context.Request.Url.Query.GetValueOrDefault("blobContainer", "test") + "/" + 
                    (context.Variables.ContainsKey("fileName") ? (string)context.Variables["fileName"] : context.Request.Url.Query.GetValueOrDefault("fileNameWithExtension", "test.mp4"))
                )" />
            </when>
            <!-- 非multipart请求沿用原逻辑 -->
            <otherwise>
                <rewrite-uri template="@(
                    context.Request.Url.Query.GetValueOrDefault("blobContainer", "test") + "/" + 
                    context.Request.Url.Query.GetValueOrDefault("fileNameWithExtension", "test.mp4")
                )" />
            </otherwise>
        </choose>
        <!-- 通用Blob Storage配置 -->
        <set-backend-service base-url="@{ return $"https://{{storage account}}.blob.core.windows.net/";}" />
        <set-method>PUT</set-method>
        <set-header name="Host" exists-action="override">
            <value>sacuksnprdiidlrawast6001.blob.core.windows.net</value>
        </set-header>
        <set-header name="X-Ms-Blob-Type" exists-action="override">
            <value>BlockBlob</value>
        </set-header>
        <set-header name="X-Ms-Version" exists-action="override">
            <value>2019-12-12</value>
        </set-header>
        <set-header name="Accept" exists-action="override">
            <value>application/json</value>
        </set-header>
        <authentication-managed-identity resource="https://storage.azure.com/" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

关键逻辑说明

  • 边界解析:从Content-Type头中提取multipart的边界字符串,用于拆分请求体。
  • 请求体解析:将请求体按边界拆分,找到包含filename=的部分(即文件字段),跳过字段头部后提取纯文件内容。
  • 头部调整:将Content-Type改为application/octet-stream,适配Blob Storage的PUT上传要求。
  • 文件名处理:可选从multipart字段中提取文件名,替代原Query参数的文件名(如果需要)。

注意事项

  • 该策略假设请求中仅包含一个文件字段,如果需要支持多文件上传,需调整拆分和提取逻辑。
  • 对于2GB级别的超大文件,需确保APIM的请求体大小限制已调整,避免因默认限制导致上传失败。
  • 解析过程会读取整个请求体到内存,若文件过大可能引发内存压力,建议结合分块上传的方式优化(通过Blob Storage的块Blob分块API实现)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:41:00