使用PHP通过共享访问密钥下载Azure Blob时遇无效头问题求助
解决Azure Blob存储PHP下载的无效头错误
你的代码出现无效头错误,核心原因是SharedKey签名构造不符合Azure规范,以及签名与请求头的版本不一致,以下是修正方案:
问题点分析
- 签名字符串结构错误:Azure SharedKey要求签名字符串必须按固定顺序包含HTTP方法、多个空值头(对应未设置的Content-Length、Content-MD5等)、排序后的x-ms开头请求头,最后才是资源路径
- x-ms-version版本不匹配:签名构造时用的是
2017-11-09,但请求头里是2017-12-12,两者必须完全一致 - 头资源拼接方式错误:不能直接把两个x-ms头合并成一个字符串,需要单独按顺序添加到签名数组中
修正后的代码
$containerName = "your-container-name"; $blobName = "your-blob-name"; $accessKey = "your-storage-account-access-key"; $storageAccount = "teststorage"; $URL = "https://{$storageAccount}.blob.core.windows.net/{$containerName}/{$blobName}"; $Date = gmdate('D, d M Y H:i:s \G\M\T'); $apiVersion = "2017-12-12"; // 统一版本号 // 构造签名字符串的数组,严格遵循Azure SharedKey顺序 $arraysign = array(); $arraysign[] = 'GET'; // HTTP方法 $arraysign[] = ''; // Content-Encoding(空值) $arraysign[] = ''; // Content-Language(空值) $arraysign[] = ''; // Content-Length(空值,GET请求可忽略) $arraysign[] = ''; // Content-MD5(空值) $arraysign[] = ''; // Content-Type(空值) $arraysign[] = ''; // Date(空值,因为用了x-ms-date) $arraysign[] = ''; // If-Modified-Since(空值) $arraysign[] = ''; // If-Match(空值) $arraysign[] = ''; // If-None-Match(空值) $arraysign[] = ''; // If-Unmodified-Since(空值) $arraysign[] = ''; // Range(空值) // 添加x-ms开头的请求头,必须按小写排序后添加 $arraysign[] = "x-ms-date:{$Date}"; $arraysign[] = "x-ms-version:{$apiVersion}"; // 添加资源路径:/存储账户名/容器名/Blob名 $arraysign[] = "/{$storageAccount}/{$containerName}/{$blobName}"; // 拼接签名字符串,用换行符分隔 $str2sign = implode("\n", $arraysign); // 生成签名:注意不要urldecode,直接用原始字符串计算HMAC $sig = base64_encode(hash_hmac('sha256', utf8_encode($str2sign), base64_decode($accessKey), true)); $authHeader = "SharedKey {$storageAccount}:{$sig}"; // 请求头必须和签名里的参数一致 $headers = [ 'Authorization: ' . $authHeader, 'x-ms-date: ' . $Date, 'x-ms-version: ' . $apiVersion, ]; // 执行下载请求(示例用curl) $ch = curl_init($URL); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 生产环境建议开启 $blobContent = curl_exec($ch); curl_close($ch); // 保存到本地文件 file_put_contents('/path/to/local/file', $blobContent);
关键说明
- 签名数组顺序不能乱:Azure对签名字符串的顺序有严格要求,必须按照规定顺序填充,未设置的头留空字符串
- 版本号统一:
x-ms-version在签名构造和请求头中必须完全相同 - 不要对签名字符串做urldecode:原始字符串直接用于HMAC计算即可,urldecode会破坏签名结构
- 生产环境建议保留
CURLOPT_SSL_VERIFYPEER为true,确保SSL安全
内容的提问来源于stack exchange,提问作者User User
相关产品推荐
相关产品推荐

