当我使用 XMLHttpRequest 和 SAS 将图像放入 azure blob 存储时格式错误
Bad format when i put an image to azure blob storage with XMLHttpRequest and SAS
我已经在 SPA 应用程序中设置了将文件发送到 Azure Blob 存储的功能。
为此,我使用了 XMLHttpRequest 和 FormData(我的用户在我公司管理的计算机上,并且所有人都可以访问 HTML5)。
为了管理安全性,在发送每个文件之前调用 Web Api 的方法以获取共享访问签名。
我将文件Content-Type以及其他信息转发给headers。
一切顺利,文件已正确发送并保存在 Azure Blob 存储中,但在传输过程中,图像文件似乎 "altered"。
它们很好,我可以下载它们并在下载后阅读它们,但我无法直接从 img 标签打开它们。
另一方面,如果我通过 Microsoft Azure 存储资源管理器发送相同的图像文件,则没有问题,图像在 img 标签中被很好地识别。
但是,在一种情况下和另一种情况下一样,content-type 被标记为 "image / jpeg"。唯一明显的区别是这两个邮件之间的 MD5 不同,而它是同一个原始文件。
根据我的发现,当通过 XMLHttpRequest 发送时,似乎在文件的开头和结尾添加了文本。
我解释一下我的代码,以便您可以指导我:
注 1:我使用打字稿(但 javascript 解决方案适合我)和 Promise。
注 2:我已经解决了所有 CORS 问题。
注 3 : 我正在使用 Azure 存储模拟器,但我尝试使用普通的 Azure 服务,问题是一样的。
这是Chrome中图片中添加的文字:
------WebKitFormBoundaryKj5cK88faAwJd4av
Content-Disposition: form-data; name="file1"; filename="test.jpg"
Content-Type: image/jpeg
[image content]
------WebKitFormBoundaryKj5cK88faAwJd4av--
我的网站 Api :
[Route(@"api/Storage/FileSas/Customers/{id:int}")]
public async Task<IHttpActionResult> GetFileSas(int id, string fileName, long? fileSize = 0, string contentType = null)
{
if (string.IsNullOrWhiteSpace(fileName))
this.ModelState.AddModelError("fileName", "File name i");
if (!fileSize.HasValue || fileSize.Value > maxFileSize)
this.ModelState.AddModelError("fileSize", "File size exceeded");
if (!this.ModelState.IsValid)
return BadRequest(this.ModelState);
var serverUrl = ConfigurationManager.AppSettings[SERVER_URL];
var container = ConfigurationManager.AppSettings[CONTAINER_NAME];
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write,
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-60),
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(60),
};
CloudBlockBlob blobFile = blobContainer.GetBlockBlobReference(Path.Combine("customers", id.ToString(), fileName));
var exists = await blobFile.ExistsAsync();
if (exists)
{
await blobFile.SnapshotAsync();
}
var signature = blobFile.GetSharedAccessSignature(policy);
return Content<string>(HttpStatusCode.Created, Path.Combine(serverUrl, container, blobFile.Name + signature));
}
我的 TypeScript 文件:
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
let formData = new FormData();
formData.append("file1", file, file.name);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
xhr.open("PUT", sasUrl, true);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('x-ms-blob-content-type', file.type);
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.User.Name);
xhr.send(formData);
})
})).catch((error) => {
console.log(error);
});
文件来自这里:
let fileInputElement1: HTMLInputElement = <HTMLInputElement>document.getElementById("file1");
let file = fileInputElement1.files[0];
我的 HTML 部分:(我正在使用敲除)
<form method="put" target="_blank" enctype="multipart/form-data">
<input type="file" name="name" value="" id="file1" />
<button data-bind="click:send"> Send</button>
</form>
如果有人有想法? ...
提前致谢。
感谢 Gaurav Mantri,他将我指向右边,这里是我的修改(仅因为我使用打字稿):
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = (event) => {
let target = <FileReader>event.target;
if (target.readyState == reader.DONE) {
var requestData = new Uint8Array(target.result);
xhr.open("PUT", sasUrl, true);
xhr.responseType = "blob";
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-blob-content-type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.Name);
xhr.send(requestData);
}
}
})
})).catch((error) => {
console.log(error);
});
现在我将开始写一个 Promise 来嵌入这个功能。
PS :我没有找到将 Gaurav Mantri 标记为答案的方法,所以我创建了我的。
PS 2 :我想给 Gaurav Mantri 一些 +1 以寻求帮助......但我不能:/
我已经在 SPA 应用程序中设置了将文件发送到 Azure Blob 存储的功能。
为此,我使用了 XMLHttpRequest 和 FormData(我的用户在我公司管理的计算机上,并且所有人都可以访问 HTML5)。 为了管理安全性,在发送每个文件之前调用 Web Api 的方法以获取共享访问签名。
我将文件Content-Type以及其他信息转发给headers。
一切顺利,文件已正确发送并保存在 Azure Blob 存储中,但在传输过程中,图像文件似乎 "altered"。
它们很好,我可以下载它们并在下载后阅读它们,但我无法直接从 img 标签打开它们。
另一方面,如果我通过 Microsoft Azure 存储资源管理器发送相同的图像文件,则没有问题,图像在 img 标签中被很好地识别。 但是,在一种情况下和另一种情况下一样,content-type 被标记为 "image / jpeg"。唯一明显的区别是这两个邮件之间的 MD5 不同,而它是同一个原始文件。
根据我的发现,当通过 XMLHttpRequest 发送时,似乎在文件的开头和结尾添加了文本。
我解释一下我的代码,以便您可以指导我: 注 1:我使用打字稿(但 javascript 解决方案适合我)和 Promise。 注 2:我已经解决了所有 CORS 问题。 注 3 : 我正在使用 Azure 存储模拟器,但我尝试使用普通的 Azure 服务,问题是一样的。
这是Chrome中图片中添加的文字:
------WebKitFormBoundaryKj5cK88faAwJd4av
Content-Disposition: form-data; name="file1"; filename="test.jpg"
Content-Type: image/jpeg
[image content]
------WebKitFormBoundaryKj5cK88faAwJd4av--
我的网站 Api :
[Route(@"api/Storage/FileSas/Customers/{id:int}")]
public async Task<IHttpActionResult> GetFileSas(int id, string fileName, long? fileSize = 0, string contentType = null)
{
if (string.IsNullOrWhiteSpace(fileName))
this.ModelState.AddModelError("fileName", "File name i");
if (!fileSize.HasValue || fileSize.Value > maxFileSize)
this.ModelState.AddModelError("fileSize", "File size exceeded");
if (!this.ModelState.IsValid)
return BadRequest(this.ModelState);
var serverUrl = ConfigurationManager.AppSettings[SERVER_URL];
var container = ConfigurationManager.AppSettings[CONTAINER_NAME];
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Write,
SharedAccessStartTime = DateTime.UtcNow.AddMinutes(-60),
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(60),
};
CloudBlockBlob blobFile = blobContainer.GetBlockBlobReference(Path.Combine("customers", id.ToString(), fileName));
var exists = await blobFile.ExistsAsync();
if (exists)
{
await blobFile.SnapshotAsync();
}
var signature = blobFile.GetSharedAccessSignature(policy);
return Content<string>(HttpStatusCode.Created, Path.Combine(serverUrl, container, blobFile.Name + signature));
}
我的 TypeScript 文件:
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
let formData = new FormData();
formData.append("file1", file, file.name);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
xhr.open("PUT", sasUrl, true);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('x-ms-blob-content-type', file.type);
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.User.Name);
xhr.send(formData);
})
})).catch((error) => {
console.log(error);
});
文件来自这里:
let fileInputElement1: HTMLInputElement = <HTMLInputElement>document.getElementById("file1");
let file = fileInputElement1.files[0];
我的 HTML 部分:(我正在使用敲除)
<form method="put" target="_blank" enctype="multipart/form-data">
<input type="file" name="name" value="" id="file1" />
<button data-bind="click:send"> Send</button>
</form>
如果有人有想法? ...
提前致谢。
感谢 Gaurav Mantri,他将我指向右边,这里是我的修改(仅因为我使用打字稿):
context.Storage.getFileSas(customerId, file)
.then((response: Interfaces.Result<string>) => {
let sasUrl = response.Data;
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = (event) => {
if (event.total > 0)
this.Progress(event.loaded * 100 / event.total);
};
xhr.onloadstart = function (e) {
}
xhr.onloadend = (e) => {
this.Progress(0);
}
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = (event) => {
let target = <FileReader>event.target;
if (target.readyState == reader.DONE) {
var requestData = new Uint8Array(target.result);
xhr.open("PUT", sasUrl, true);
xhr.responseType = "blob";
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('x-ms-blob-type', 'BlockBlob');
xhr.setRequestHeader('Content-Type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-blob-content-type', file.type || 'application/octet-stream');
xhr.setRequestHeader('x-ms-version', "2016-05-31");
xhr.setRequestHeader('x-ms-meta-CustomerId', customerId);
xhr.setRequestHeader('x-ms-meta-UserId', context.User.Id.toString());
xhr.setRequestHeader('x-ms-meta-UserName', context.User.Name);
xhr.send(requestData);
}
}
})
})).catch((error) => {
console.log(error);
});
现在我将开始写一个 Promise 来嵌入这个功能。
PS :我没有找到将 Gaurav Mantri 标记为答案的方法,所以我创建了我的。 PS 2 :我想给 Gaurav Mantri 一些 +1 以寻求帮助......但我不能:/