排查 Azure 存储帐户中的客户端应用程序错误

本文介绍如何使用 Azure Monitor 中的指标、 客户端日志和资源日志来调查客户端应用程序错误。

诊断错误

应用程序的用户可能会通知客户端应用程序报告的错误。 Azure Monitor 还会记录存储服务(如 NetworkError、ClientTimeoutErrorAuthorizationError)) 的不同响应类型 (ResponseType 维度的计数。 虽然 Azure Monitor 仅记录不同错误类型的计数,但可以通过检查服务器端、客户端和网络日志来获取有关各个请求的更多详细信息。 通常,存储服务返回的 HTTP 状态代码会指示请求失败的原因。

注意

请记住,应该会看到一些间歇性错误。 例如,暂时性网络条件导致的错误或应用程序错误。

以下资源有助于了解与存储相关的状态和错误代码:

客户端正在接收 HTTP 403 (禁止) 消息

如果客户端应用程序引发 HTTP 403 (禁止) 错误,则可能原因是客户端在发送存储请求时使用过期的共享访问签名 (SAS () ,尽管其他可能的原因包括时钟偏差、无效密钥和空标头) 。

使用适用于 .NET 的存储客户端库可以收集与应用程序执行的存储操作相关的客户端日志数据。 有关详细信息,请参阅 使用 .NET 存储客户端库进行客户端日志记录

下表显示了存储客户端库生成的客户端日志示例,其中说明了此问题的发生:

Source 冗长 冗长 客户端请求 ID 操作文本
Microsoft.Azure.Storage Information 3 85d077ab-... Starting operation with location Primary per location mode PrimaryOnly.
Microsoft.Azure.Storage Information 3 85d077ab -... Starting synchronous request to <https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#Synchronous_request>
Microsoft.Azure.Storage Information 3 85d077ab -... Waiting for response.
Microsoft.Azure.Storage 警告 2 85d077ab -... Exception thrown while waiting for response: The remote server returned an error: (403) Forbidden.
Microsoft.Azure.Storage Information 3 85d077ab -... Response received. Status code = 403, Request ID = <Request ID>, Content-MD5 = , ETag = .
Microsoft.Azure.Storage 警告 2 85d077ab -... Exception thrown during the operation: The remote server returned an error: (403) Forbidden..
Microsoft.Azure.Storage Information 3 85d077ab -... Checking if the operation should be retried. Retry count = 0, HTTP status code = 403, Exception = The remote server returned an error: (403) Forbidden..
Microsoft.Azure.Storage Information 3 85d077ab -... The next location has been set to Primary, based on the location mode.
Microsoft.Azure.Storage 错误 1 85d077ab -... Retry policy did not allow for a retry. Failing with The remote server returned an error: (403) Forbidden.

在此方案中,应在客户端将令牌发送到服务器之前调查 SAS 令牌过期的原因:

  • 通常,创建可供客户端立即使用的 SAS 时,不应设置开始时间。 如果使用当前时间生成 SAS 的主机与存储服务之间的时钟差异很小,则存储服务可能会收到尚无效的 SAS。

  • 不要在 SAS 上设置非常短的到期时间。 同样,生成 SAS 的主机与存储服务之间的小时钟差异可能会导致 SAS 比预期更早过期。

  • 例如, svSAS 密钥中的 version 参数 (=2015-04-05) 是否与正在使用的存储客户端库的版本匹配? 建议始终使用最新版本的存储客户端库。

  • 如果重新生成存储访问密钥,则任何现有的 SAS 令牌都可能失效。 如果为客户端应用程序缓存而生成过期时间较长的 SAS 令牌,则可能会出现此问题。

如果使用存储客户端库生成 SAS 令牌,则很容易生成有效的令牌。 但是,如果使用存储 REST API 并手动构造 SAS 令牌,请参阅 使用共享访问签名委派访问

客户端正在接收 HTTP 404 (找不到) 消息

如果客户端应用程序从服务器收到 HTTP 404 (找不到) 消息,这意味着存储服务中不存在客户端尝试使用 (的对象,例如实体、表、Blob、容器或队列) 。 有多种可能的原因,例如:

  • 客户端或其他进程之前删除了 对象。

  • 共享访问签名 (SAS) 授权问题。

  • 客户端 JavaScript 代码没有访问对象的权限。

  • 网络故障。

客户端或其他进程之前删除了 对象

在客户端尝试读取、更新或删除存储服务中的数据的情况下,很容易在存储资源日志中识别以前从存储服务中删除了有关对象的操作。 通常,日志数据显示其他用户或进程删除了对象。 当客户端删除对象时, (服务器端) 显示 Azure Monitor 日志。

在客户端尝试插入对象的情况下,鉴于客户端正在创建新对象,导致 HTTP 404 (找不到) 响应的原因可能并不明显。 但是,如果客户端正在创建 Blob,它必须能够找到 Blob 容器。 如果客户端正在创建消息,它必须能够找到队列。 如果客户端要添加行,它必须能够找到表。

可以使用存储客户端库中的客户端日志来更好地了解客户端何时向存储服务发送特定请求。

存储客户端库生成的以下客户端日志说明了当客户端找不到它正在创建的 Blob 的容器时出现的问题。 此日志包括以下存储操作的详细信息:

请求 ID 操作
07b26a5d-... DeleteIfExists 用于删除 Blob 容器的 方法。 此操作包括一个HEAD请求,请求检查是否存在容器。
e2d06d78... CreateIfNotExists 方法,用于创建 Blob 容器。 此操作包括一个 HEAD 请求,用于检查容器是否存在。 返回 HEAD 404 消息,但会继续。
de8b1c3c-... UploadFromStream 创建 Blob 的 方法。 请求 PUT 失败并显示 404 消息

日志条目:

请求 ID 操作文本
07b26a5d-... Starting synchronous request to https://domemaildist.blob.core.windows.net/azuremmblobcontainer.
07b26a5d-... StringToSign = HEAD............x-ms-client-request-id:07b26a5d-....x-ms-date:Tue, 03 Jun 2014 10:33:11 GMT.x-ms-version:2014-02-14./domemaildist/azuremmblobcontainer.restype:container.
07b26a5d-... Waiting for response.
07b26a5d-... Response received. Status code = 200, Request ID = eeead849-...Content-MD5 = , ETag = &quot;0x8D14D2DC63D059B&quot;.
07b26a5d-... Response headers were processed successfully, proceeding with the rest of the operation.
07b26a5d-... Downloading response body.
07b26a5d-... Operation completed successfully.
07b26a5d-... Starting synchronous request to https://domemaildist.blob.core.windows.net/azuremmblobcontainer.
07b26a5d-... StringToSign = DELETE............x-ms-client-request-id:07b26a5d-....x-ms-date:Tue, 03 Jun 2014 10:33:12 GMT.x-ms-version:2014-02-14./domemaildist/azuremmblobcontainer.restype:container.
07b26a5d-... Waiting for response.
07b26a5d-... Response received. Status code = 202, Request ID = 6ab2a4cf-..., Content-MD5 = , ETag = .
07b26a5d-... Response headers were processed successfully, proceeding with the rest of the operation.
07b26a5d-... Downloading response body.
07b26a5d-... Operation completed successfully.
e2d06d78-... Starting asynchronous request to https://domemaildist.blob.core.windows.net/azuremmblobcontainer.
e2d06d78-... StringToSign = HEAD............x-ms-client-request-id:e2d06d78-....x-ms-date:Tue, 03 Jun 2014 10:33:12 GMT.x-ms-version:2014-02-14./domemaildist/azuremmblobcontainer.restype:container.
e2d06d78-... Waiting for response.
de8b1c3c-... Starting synchronous request to https://domemaildist.blob.core.windows.net/azuremmblobcontainer/blobCreated.txt.
de8b1c3c-... StringToSign = PUT...64.qCmF+TQLPhq/YYK50mP9ZQ==........x-ms-blob-type:BlockBlob.x-ms-client-request-id:de8b1c3c-....x-ms-date:Tue, 03 Jun 2014 10:33:12 GMT.x-ms-version:2014-02-14./domemaildist/azuremmblobcontainer/blobCreated.txt.
de8b1c3c-... Preparing to write request data.
e2d06d78-... Exception thrown while waiting for response: The remote server returned an error: (404) Not Found..
e2d06d78-... Response received. Status code = 404, Request ID = 353ae3bc-..., Content-MD5 = , ETag = .
e2d06d78-... Response headers were processed successfully, proceeding with the rest of the operation.
e2d06d78-... Downloading response body.
e2d06d78-... Operation completed successfully.
e2d06d78-... Starting asynchronous request to https://domemaildist.blob.core.windows.net/azuremmblobcontainer.
e2d06d78-... StringToSign = PUT...0.........x-ms-client-request-id:e2d06d78-....x-ms-date:Tue, 03 Jun 2014 10:33:12 GMT.x-ms-version:2014-02-14./domemaildist/azuremmblobcontainer.restype:container.
e2d06d78-... Waiting for response.
de8b1c3c-... Writing request data.
de8b1c3c-... Waiting for response.
e2d06d78-... Exception thrown while waiting for response: The remote server returned an error: (409) Conflict..
e2d06d78-... Response received. Status code = 409, Request ID = c27da20e-..., Content-MD5 = , ETag = .
e2d06d78-... Downloading error response body.
de8b1c3c-... Exception thrown while waiting for response: The remote server returned an error: (404) Not Found..
de8b1c3c-... Response received. Status code = 404, Request ID = 0eaeab3e-..., Content-MD5 = , ETag = .
de8b1c3c-... Exception thrown during the operation: The remote server returned an error: (404) Not Found..
de8b1c3c-... Retry policy did not allow for a retry. Failing with The remote server returned an error: (404) Not Found..
e2d06d78-... Retry policy did not allow for a retry. Failing with The remote server returned an error: (409) Conflict..

在此示例中,日志显示客户端正在交错来自 CreateIfNotExists 方法的请求 (请求 ID e2d06d78...) 方法 UploadFromStream (de8b1c3c-...) 。由于客户端应用程序异步调用这些方法,因此会发生这种交错。 修改客户端中的异步代码,以确保在尝试将任何数据上传到该容器中的 Blob 之前创建容器。 理想情况下,应提前创建所有容器。

共享访问签名 (SAS) 授权问题

如果客户端应用程序尝试使用不包含操作所需权限的 SAS 密钥,存储服务会向客户端返回 HTTP 404 (“找不到”) 消息。 同时,在 Azure Monitor 指标中,还会看到 ResponseType 维度的 AuthorizationError

调查客户端应用程序尝试执行未向其授予权限的操作的原因。

客户端 JavaScript 代码没有访问对象的权限

如果使用 JavaScript 客户端,并且存储服务返回 HTTP 404 消息,检查浏览器中的以下 JavaScript 错误:

SEC7120: http://localhost:56309 Access-Control-Allow-Origin 标头中找不到源。
SCRIPT7002:XMLHttpRequest:网络错误0x80070005,访问被拒绝。

注意

在排查客户端 JavaScript 问题时,可以使用 Internet Explorer 中的 F12 开发人员工具跟踪浏览器与存储服务之间交换的消息。

发生这些错误的原因是 Web 浏览器实现了 相同的源策略 安全限制,该限制阻止网页从页面所在的域调用不同域中的 API。

若要解决 JavaScript 问题,可以为客户端正在访问的存储服务配置跨源资源共享 (CORS) 。 有关详细信息,请参阅 跨源资源共享 (CORS) Azure 存储服务支持

以下代码示例演示如何配置 Blob 服务,以允许在 Contoso 域中运行的 JavaScript 访问 Blob 存储服务中的 Blob:

var connectionString = Constants.connectionString;

 BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);

 BlobServiceProperties sp = blobServiceClient.GetProperties();

 // Set the service properties.
 sp.DefaultServiceVersion = "2013-08-15";
 BlobCorsRule bcr = new BlobCorsRule();
 bcr.AllowedHeaders = "*";

 bcr.AllowedMethods = "GET,POST";
 bcr.AllowedOrigins = "http://www.contoso.com";
 bcr.ExposedHeaders = "x-ms-*";
 bcr.MaxAgeInSeconds = 5;
 sp.Cors.Clear();
 sp.Cors.Add(bcr);
 blobServiceClient.SetProperties(sp);

网络故障

在某些情况下,丢失的网络数据包可能会导致存储服务将 HTTP 404 消息返回到客户端。 例如,当客户端应用程序从表服务中删除实体时,会看到客户端从表服务引发存储异常,报告“HTTP 404 (找不到) ”状态消息。 调查表存储服务中的表时,会看到该服务确实按照请求删除了实体。

客户端中的异常详细信息包括表服务为请求分配的请求 ID (7e84f12d...) :可以使用此信息在 Azure Monitor 中的存储资源日志中搜索 描述日志条目操作的身份验证方式的字段 来查找请求详细信息。 还可以使用指标来确定何时发生此类故障,然后根据指标记录此错误的时间搜索日志文件。 此日志条目显示删除失败,并显示“HTTP (404) 客户端其他错误”状态消息。 同一日志条目还包括客户端在 client-request-id (813ea74f...) 列中生成的请求 ID。

服务器端日志还包括另一个具有相同值的条目 client-request-id (813ea74f...) ,用于对同一实体和同一客户端成功执行删除操作。 此成功的删除操作发生在失败的删除请求之前不久。

这种情况的最可能原因是客户端向表服务发送了实体的删除请求,该请求成功但未收到来自服务器的确认 (可能是由于) 的临时网络问题。 然后,客户端使用相同的) 自动重试操作 (client-request-id ,并且此重试失败,因为实体已被删除。

如果此问题经常发生,则应调查客户端无法从表服务接收确认的原因。 如果问题是间歇性的,则应捕获“HTTP (404) 找不到”错误,并将其记录在客户端中,但允许客户端继续。

客户端正在接收 HTTP 409 (冲突) 消息

当客户端删除 Blob 容器、表或队列时,需要一小段时间才能再次提供该名称。 如果客户端应用程序中的代码删除并立即使用相同的名称重新创建 Blob 容器,则 CreateIfNotExists 该方法最终会失败并显示 HTTP 409 (冲突) 错误。

如果删除/重新创建模式常见,则客户端应用程序在创建新容器时应使用唯一的容器名称。

指标显示低 PercentSuccess 或分析日志条目具有事务状态为 ClientOtherErrors 的操作

等于 Success 值的 ResponseType 维度会根据其 HTTP 状态代码捕获成功操作的百分比。 状态代码为 2XX 的操作将计为成功,而状态代码在 3XX、4XX 和 5XX 范围内的操作将计为失败并降低 Success 指标值。 在存储资源日志中,这些操作的事务状态为 ClientOtherError 进行记录。

这些操作已成功完成,因此不会影响其他指标,例如可用性。 成功执行但可能导致 HTTP 状态代码失败的操作的一些示例包括:

  • ResourceNotFound (找不到 404) ,例如,从 GET 请求到不存在的 Blob。
  • ResourceAlreadyExists (Conflict 409) ,例如,来自 CreateIfNotExist 资源已存在的操作。
  • ConditionNotMet (Not Modified 304) ,例如,来自条件操作,例如,客户端发送 ETag 值和 HTTP If-None-Match 标头以请求图像时,仅当自上次操作以来已更新图像时。

可以在“常见 REST API 错误代码”页上找到存储服务返回的 常见 REST API 错误代码列表。

另请参阅

联系我们寻求帮助

如果你有任何疑问或需要帮助,请创建支持请求联系 Azure 社区支持。 还可以向 Azure 反馈社区提交产品反馈。