使用Python Requests调用Azure文件服务REST API失败求助
作为经常和Azure存储服务打交道的开发者,我来帮你一步步排查这个问题。你返回的b'\xef\xbb\xbf<?xml ver...'其实是带UTF-8 BOM的XML错误响应,先解码看看具体错误信息,但先从最常见的几个问题入手:
1. 最可能的问题:x-ms-date格式不符合要求
Azure存储服务要求x-ms-date必须是RFC 1123格式(比如Mon, 16 Apr 2018 06:22:15 GMT),但你用的是2018-04-17 06:22:15.181620,这个格式Azure完全无法识别,直接会导致授权验证失败。
你可以用Python的datetime和pytz模块生成正确的日期字符串:
from datetime import datetime import pytz # 生成UTC时区的RFC1123格式日期 current_time = datetime.now(pytz.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
2. SharedKey签名计算可能出错
Azure的SharedKey授权是基于请求的关键信息(HTTP方法、日期、资源路径等)生成的,只要其中一个参数不对,签名就会无效。你需要确保签名字符串的构造完全符合规则:
针对你这个列出共享的GET请求,签名字符串的结构应该是这样的(注意空行对应空的请求头/内容):
GET\n \n \n \n \n \n \n \n \n \n \n \n x-ms-date:{你的正确日期}\nx-ms-version:2017-07-29\n/{你的存储账户名}/?comp=list
然后用HMAC-SHA256加密,再Base64编码。我给你写了一段完整的签名生成代码,可以直接参考:
import hmac import hashlib import base64 account_name = "zedongstorageaccount" account_key = "你的存储账户访问密钥" # 注意这里是账户的原始密钥,不是你之前生成的签名 # 构造签名字符串(用上面生成的current_time) sign_string = f"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:{current_time}\nx-ms-version:2017-07-29\n/{account_name}/?comp=list" # 计算签名 encoded_sign = sign_string.encode('utf-8') encoded_key = base64.b64decode(account_key) signature = hmac.new(encoded_key, encoded_sign, hashlib.sha256).digest() shared_key = base64.b64encode(signature).decode()
3. 先解析错误XML,获取具体问题
你可以先把返回的内容解码,解析XML得到具体的错误代码和消息,这样能更精准定位问题:
import xml.etree.ElementTree as ET # 解码内容(处理开头的BOM) content = r.content.decode('utf-8-sig') # 解析XML root = ET.fromstring(content) # 提取错误信息 error_code = root.find('.//Code').text error_message = root.find('.//Message').text print(f"错误代码: {error_code}") print(f"错误消息: {error_message}")
比如如果返回AuthenticationFailed,那大概率就是日期格式或签名的问题;如果是InvalidResourceName,就要检查账户名或URL是否写错。
完整的请求示例代码
把上面的步骤整合起来,这里给你一个可以直接运行的完整示例:
import requests from datetime import datetime import pytz import hmac import hashlib import base64 import xml.etree.ElementTree as ET # 配置信息 account_name = "zedongstorageaccount" account_key = "替换成你的存储账户访问密钥" api_version = "2017-07-29" url = f"https://{account_name}.file.core.windows.net/?comp=list" # 生成正确的日期格式 current_time = datetime.now(pytz.utc).strftime('%a, %d %b %Y %H:%M:%S GMT') # 构造并计算签名 sign_string = f"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:{current_time}\nx-ms-version:{api_version}\n/{account_name}/?comp=list" encoded_sign = sign_string.encode('utf-8') encoded_key = base64.b64decode(account_key) signature = hmac.new(encoded_key, encoded_sign, hashlib.sha256).digest() shared_key = base64.b64encode(signature).decode() # 构造请求头 headers = { 'x-ms-date': current_time, 'Authorization': f'SharedKey {account_name}:{shared_key}', 'x-ms-version': api_version } # 发送请求 response = requests.get(url, headers=headers) # 处理响应 if response.status_code == 200: print("请求成功!返回内容:") print(response.content.decode('utf-8')) else: print(f"请求失败,状态码: {response.status_code}") content = response.content.decode('utf-8-sig') root = ET.fromstring(content) error_code = root.find('.//Code').text error_message = root.find('.//Message').text print(f"错误代码: {error_code}") print(f"错误消息: {error_message}")
按照这个代码调整后,应该就能正常访问Azure文件服务了。如果还有问题,把解析出来的错误代码发出来,我再帮你进一步排查。
内容的提问来源于stack exchange,提问作者zedong

