Azure:无法从 Azure 函数 HttpTrigger 读取 Blob 文本(400 - 错误请求错误)

Posted

技术标签:

【中文标题】Azure:无法从 Azure 函数 HttpTrigger 读取 Blob 文本(400 - 错误请求错误)【英文标题】:Azure: Cannot Read Blob Text from Azure Function HttpTrigger (400 - Bad Request Error) 【发布时间】:2017-09-07 06:03:33 【问题描述】:

我无法读取存储在 Azure (Blob) Storage 上的 blob 中的文本。

blob 仅包含单行文本(字符串)。 Blob 通过 Azure Functions HttpTrigger (C#) 填充文本,后者通过 POST 接收文本并将文本保存到具有用户指定名称的 Blob。保存 blob 时,名称将全部转换为小写。

然后用户可以访问一个简单的 html 网页并将 blob 的名称输入到表单中。当用户在 HTML 表单上单击“提交”时,会针对不同的 Azure Function API 执行 POST。此函数访问 blob 并从中读取文本。每当我从 Azure Functions 中或使用 Postman 测试函数时,它都能正常工作(我得到了 blob 文本)。

当我尝试使用网页与 API 交互时,当 Azure 函数从 blob 中读取时,我收到“400 - 错误请求”。请看下面的详细信息:

从 Postman 正常工作的 API 日志:

2017-04-11T20:19:14.340 函数已启动(Id=ea82f5c6-4345-40cc-90a5-1cb1cad78b7b)

2017-04-11T20:19:14.340 C# HTTP 触发函数处理了一个请求。

2017-04-11T20:19:14.340 来自 POST 的数据:blobName=TestBlob1submit=SubmitButtonText

2017-04-11T20:19:14.340 Blob 名称为:testblob1

2017-04-11T20:19:14.340 访问 Azure 存储帐户。

2017-04-11T20:19:14.402 Blob 中的文本:Hello world 测试!

2017-04-11T20:19:14.402 功能完成(成功,Id=ea82f5c6-4345-40cc-90a5-1cb1cad78b7b)

API 不通过 HTML 表单工作的日志:

2017-04-11T20:19:52.594 函数已启动(Id=1b1a39b6-0ab8-4673-bbf0-ae0006f7f7cf)

2017-04-11T20:19:52.594 C# HTTP 触发器函数处理了一个请求。

2017-04-11T20:19:52.594 来自 POST 的数据:blobName=TestBlob1

submit=检索 Blob 文本

2017-04-11T20:19:52.594 Blob 名称为:testblob1

2017-04-11T20:19:52.594 访问 Azure 存储帐户。

2017-04-11T20:19:52.626 功能完成(失败,Id=1b1a39b6-0ab8-4673-bbf0-ae0006f7f7cf)

2017-04-11T20:19:52.672 执行函数时出现异常:Functions.Austin-SteelThread-HttpTrigger-DisplayBlobText。 Microsoft.WindowsAzure.Storage:远程服务器返回错误:(400) Bad Request。

这里是有问题的 Azure 函数:

#r "Microsoft.WindowsAzure.Storage"
using System;
using System.IO;
using System.Net;
using System.Text;
using Microsoft.Azure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log, Binder binder)

    log.Info("C# HTTP trigger function processed a request.");

    // Get text passed in POST
    string postData = await req.Content.ReadAsStringAsync();
    log.Info("Data from POST: " + postData);

    // Format blobName string to remove unwanted text
    // Help from http://***.com/questions/9505400/extract-part-of-a-string-between-point-a-and-b
    int startPos = postData.LastIndexOf("blobName=") + "blobName=".Length;
    int length = postData.IndexOf("submit=") - startPos;
    string blobName = postData.Substring(startPos, length);
    blobName = blobName.ToLower();      // Name of blob must be all lower-case

    log.Info("Blob name is: " + blobName);

    // START BLOB READING
    log.Info("Accessing Azure Storage account.");
    string containerAndBlob = "usertext-container/blob-" + blobName;

    var attributes = new Attribute[]
    
         new StorageAccountAttribute("[StorageAccountName]"),
         new BlobAttribute(containerAndBlob)
    ;

    try
    
        userBlobText = await binder.BindAsync<string>(attributes);
    
    catch (StorageException ex)
    
        var requestInformation = ex.RequestInformation;
        var extendedInformation = requestInformation.ExtendedErrorInformation;

        if (extendedInformation == null)
        
            log.Info("No Extended Error Information!");
            log.Info(requestInformation.HttpStatusMessage);
        
        else
        
            log.Info(requestInformation.HttpStatusMessage);

            var errorMessage = string.Format("(0) 1", extendedInformation.ErrorCode, extendedInformation.ErrorMessage);

            var errorDetails = extendedInformation.AdditionalDetails.Aggregate("", (s, pair) =>
            
                return s + string.Format("0=1,", pair.Key, pair.Value);
            );

            log.Info(errorMessage + ": Error Details: " + errorDetails);
        
    

    log.Info("Text in Blob: " + userBlobText.ToString());
    // END BLOB READING

    return userBlobText == null
        ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass blob name in the request body.")
        : req.CreateResponse(HttpStatusCode.OK, "Your blob stored the text: " + userBlobText.ToString());

我该如何解决这个问题,以便函数读取 blob 文本并且网络浏览器显示 blob 的文本(现在我只得到一个空字符串)?提前谢谢你。

【问题讨论】:

您实际上应该将您的异常转换为 StorageException。然后您将能够看到有关 400 错误的更多详细信息。我建议查看异常的 RequestInformation 属性。 HTH。 我尝试实现这里提到的扩展信息link,但我的错误没有扩展信息。仅 400 - 错误请求。 【参考方案1】:

您应该利用绑定引擎,而不是手动连接到 Blob 存储。将binder 参数添加到您的函数中,然后使用它来检索文件:

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, 
    TraceWriter log, Binder binder)

    // Do await, not .Result
    string postData = await req.Content.ReadAsStringAsync();

    // ... get your HTTP parameters here

    var attributes = new Attribute[]
    
         new StorageAccountAttribute(accountName),
         new BlobAttribute(blobName) // blobName should have "container/blob" format
    ;

    var userBlobText = await binder.BindAsync<string>(attributes);
    // do whatever you want with this blob...

【讨论】:

当我使用活页夹执行您的建议时,我收到此错误:error CS1503: Argument 1: cannot convert from 'System.Attribute[]' to 'System.Attribute' IBinder更改为Binder 这可以解决属性问题。现在我得到错误:'string': type used in a using statement must be implicitly convertible to 'System.IDisposable' 用普通赋值替换using 是的,在声明性绑定的情况下,function.json 的“连接”参数中的连接名称(不是连接字符串)

以上是关于Azure:无法从 Azure 函数 HttpTrigger 读取 Blob 文本(400 - 错误请求错误)的主要内容,如果未能解决你的问题,请参考以下文章

无法从 Visual Studio 2017 调试和发布 Azure 函数

Azure 函数无法访问 Azure Blob

从Azure获取令牌以访问Microsoft Graph后无法调用函数

无法从 Azure Function 中的 ffprobe 获取输出

如何从 azure 函数应用程序将文件发送到 azure 存储

部署 Azure 函数时无法从程序集“System.Runtime”加载类型“System.IO.Path”