#javascript #reactjs #blob #fetch-api #webapi
#javascript #reactjs #большой двоичный объект #fetch-api #webapi
Вопрос:
Я начал разработку нового веб-приложения на основе Web API / ReactJS, у меня есть метод api со следующей подписью:
[HttpGet("{clientid}/download/{filename}")]
public async Task<HttpResponseMessage> DownloadFileAsync([FromRoute] int clientid, [FromRoute] string filename)
На стороне ReactJS я пытаюсь получить поток из моего api, выполняя следующий JS-код:
await fetch(`someservice/${clientid}/download/${fileName}`, { responseType: "arraybuffer" })
.then(function (res) {
var response = res;
return response.body;
})
.then(function (blob) {
// Create an object URL for the blob object
const url = URL.createObjectURL(blob);
console.log(url);
// Create a new anchor element
const a = document.createElement('a');
a.href = url;
a.download = fileName || 'download';
a.click();
})
Проблема в том, что я получаю ответ json, подобный приведенному ниже, вместо двоичных данных.
{
"version":{
"major":1,
"minor":1,
"build":-1,
"revision":-1,
"majorRevision":-1,
"minorRevision":-1
},
"content":{
"headers":[
{
"Key":"Content-Type",
"Value":[
"application/octet-stream"
]
},
{
"Key":"Content-Length",
"Value":[
"119503316"
]
}
]
},
"statusCode":200,
"reasonPhrase":"OK",
"headers":[
],
"trailingHeaders":[
],
"requestMessage":null,
"isSuccessStatusCode":true
}
Обновление 1:
Я изменил метод выборки, как показано ниже, и теперь получаю только частичные данные:
await fetch(`someservice/${clientid}/download/${fileName}`)
.then(function (res) {
var response = res;
return response.body;
})
.then(function (body) {
var reader = body.getReader()
var resu<
var charsReceived = 0;
reader.read().then(function process({ done, value }) {
if (done) {
console.log("Stream complete");
return;
}
// value for fetch streams is a Uint8Array
const chunk = value;
charsReceived = value.length;
console.log(charsReceived);
result = chunk;
// Read some more, and call this function again
return reader.read().then(process);
});
return resu<
})
.then(function (blob) {
// Create an object URL for the blob object
const url = URL.createObjectURL(blob);
console.log(url);
// Create a new anchor element
const a = document.createElement('a');
a.href = url;
a.download = fileName || 'download';
a.click();
})
Обновление 2:
Все еще есть такое же событие получения частичных данных после использования ArrayBuffer
await fetch(`someservice/${clientid}/download/${fileName}`)
.then(function (res) {
var response = res;
return response.arrayBuffer();
})
.then(function (blob) {
console.log(blob);
// Create an object URL for the blob object
const url = URL.createObjectURL(blob);
console.log(url);
// Create a new anchor element
const a = document.createElement('a');
a.href = url;
a.download = fileName || 'download';
a.click();
})
Комментарии:
1. Вы можете преобразовать ответ, используя
response.arrayBuffer()
метод в ответе выборки2. Спасибо за ваш повтор, но у меня все та же проблема.
Ответ №1:
У меня возникли две проблемы, и я исправил свой javascript, как показано ниже:
await fetch(`lynxdumper/${clientid}/download/${fileName}`, { responseType: "blob" })
.then((response) => {
return response.blob();
})
.then(function (file) {
console.log(file);
let blob = new Blob([file], { type: 'dmp' });
console.log(blob);
// Create an object URL for the blob object
const url = URL.createObjectURL(blob);
console.log(url);
// Create a new anchor element
const a = document.createElement('a');
a.href = url;
a.download = fileName || 'download';
a.click();
})
И я изменил сторону api с:
Task<HttpResponseMessage> to Task<ActionResult<byte[]>>
Полный код моего метода приведен ниже:
[HttpGet("{clientid}/download/{filename}")]
public async Task<IActionResult> DownloadDumpFileAsync([FromRoute] int clientid, [FromRoute] string filename)
{
var client = clientRepository.GetClientById(clientid);
var channel = GrpcChannel.ForAddress(client.BaseUrl.AbsoluteUri, new GrpcChannelOptions
{
HttpClient = CreateHttpClient(),
MaxReceiveMessageSize = 1024 * 1024 * 1024,
MaxSendMessageSize = 1024 * 1024 * 1024
});
var serviceclient = new DumperService.DumperServiceClient(channel);
var replay = await serviceclient.DownloadAsync(new DowloadRequest { Filename = filename });
var bytes = replay.Chunk.ToByteArray();
return Ok(new MemoryStream(bytes));
}