Не удается загрузить большой двоичный объект Azure с Java

#java #azure

Вопрос:

Это довольно странная проблема. Мне нужно сгенерировать подписанный URL-адрес, которым можно поделиться с другими для загрузки файла в течение определенного срока. Очевидно, что, поскольку я говорю «подписано», вам не следует требовать каких-либо предварительных разрешений для загрузки. Ниже приведен код, который я использую для загрузки и скачивания

   private final BlobSasPermission blobSasPermission = new BlobSasPermission()
      .setReadPermission(true);

  public String uploadAndGenerateSignedUrl(String filePath, String uploadPath) {
    BlobClient blobClient = containerClient.getBlobClient(uploadPath);
    blobClient.uploadFromFile(filePath);

    BlockBlobClient blockBlobClient = blobClient.getBlockBlobClient();
    BlobServiceSasSignatureValues blobServiceSasSignatureValues = new BlobServiceSasSignatureValues(
        OffsetDateTime.now().plusMinutes(azureConfiguration.getExpiryMin()), blobSasPermission);
    return blockBlobClient.getBlobUrl()   "?"   blockBlobClient
        .generateSas(blobServiceSasSignatureValues);
  }

  public void downloadFromUrl(String signedUrl, File file) throws IOException {
    OkHttpClient client = SharedClient.getNewSharedClientBuilder().build();

    Request request = new Request.Builder()
        .url(signedUrl)
        .build();

    okhttp3.Response response = client.newCall(request).execute();
    InputStream inputStream = response.body().byteStream();
    FileUtils.copyInputStreamToFile(inputStream, file);
  }

 

Теперь, когда я открываю сгенерированный URL-адрес в браузере, файл успешно загружен. Аналогично, запуск GET in PostMan для этого URL-адреса работает нормально. Однако, когда я отправляю тот же URL-адрес методу загрузки, он завершается ошибкой 403, в которой говорится, что серверу не удалось аутентифицировать запрос. Я понятия не имею о причине этого. Я попытался добавить протоколы http и https к подписанному URL-адресу, но это также не помогло.

Редактировать:

Добавление сообщения об ошибке
Response{protocol=http/1.1, code=403, message=Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature., url=https://{account}.blob.core.windows.net/{container}/MDConnector/MDTest/Test_16269425/2021-07-24/1627125196450/NormalFile.md?sv=2019-07-07amp;se=2021-07-24T12:13:18Zamp;sr=bamp;sp=ramp;sig=BoTaZ9iEA8Cdcbscf6zpWTol32 52rfVyLNDMBlLr1Q=}

Комментарии:

1. Вы уверены, что в вашем браузере или почтальоне не было файла cookie, доступного для авторизации, который был случайно использован. Не имея полной ошибки, я бы предположил, что вызываемая конечная точка требует подтверждения подлинности в какой-либо форме.

2. Не тот случай. Я тоже зарегистрировался инкогнито. Одна необычная вещь, которую я также заметил, заключается в том, что всякий раз, когда добавляется новый файл, он показывает ошибку при загрузке. Но через некоторое время он начинает работать нормально

Ответ №1:

Я могу воспроизвести эту проблему. По сути, проблема возникает из-за входа в вашу подпись токена SAS. При создании URL -адреса знак интерпретируется как пробел, и из-за этого ваша авторизация не выполняется.

Все, что вам нужно сделать, это кодировать URL-адрес вашего токена SAS. Как только вы это сделаете, ваш запрос должен сработать просто отлично. Пожалуйста, ознакомьтесь с примером кода ниже:

 package com.company;

import okhttp3.OkHttpClient;
import okhttp3.Request;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public class Main {

    public static void main(String[] args) throws IOException {
        String url = "https://account.blob.core.windows.net/container/blob.png";
        String sasToken = "sv=2020-04-08amp;st=2021-07-24T14:33:27Zamp;se=2021-07-31T14:33:00Zamp;sr=bamp;sp=racamp;sig=QytPc/ 0z/eHd u4WO0HGOFDOZjVfB vbQdbR6FFrl4=";//Notice the " " sign in SAS token.
        sasToken = URLEncoder.encode(sasToken, StandardCharsets.UTF_8.toString());
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url "?"  sasToken).build();
        okhttp3.Response response = client.newCall(request).execute();
        InputStream inputStream = response.body().byteStream();
    }
}
 

Комментарии:

1. Это работает безупречно. Спасибо. Вы правы, насчет кодировки. Хотя теперь, если я использую сгенерированный URL-адрес в браузере, он не работает из-за кодировки. Не то чтобы у меня для этого были какие-то требования, но могли бы мы найти альтернативу, чтобы созданный URL-адрес работал в любом случае ?

2. Я ранее работал с URL-адресами, возглавляемыми s3, но там не сталкивался с такой проблемой. Я сопоставлю сгенерированные URL-адреса и проведу некоторое расследование, возможно, найду там что-то полезное