Squeak.ru - шаблоны программирования

API REST службы хранилища Azure для блочных BLOB-объектов: проблема с длиной содержимого

Я пытаюсь использовать Azure Storage rest api для отправки типа блочного двоичного объекта, но проблема заключается в том, что длина содержимого должна быть известна заранее для загрузки.

Есть ли у нас обходной путь для случаев, когда необходимо ретранслировать inputStream, не имея доступной информации о длине.

String accesskey = "accesskey";
String storageAccount = "storageAccount";
String containerName = "containerName";
String workgroupId = UUID.randomUUID().toString();
String objectId = "1." + UUID.randomUUID().toString();
String blobName = getAzureAccessKey(containerName, workgroupId, objectId);
String version = "2018-03-28";
String putData = "testData";

SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String currentDate = fmt.format(Calendar.getInstance().getTime()) + " GMT";

String urlResource = "/"+ Paths.get(storageAccount, containerName, blobName).toString();
String headerResource = "x-ms-blob-type:BlockBlob\nx-ms-date:" + currentDate + "\nx-ms-version:" + version;
String putUrl = "https://" + storageAccount + ".blob.core.windows.net/" + containerName + "/" + blobName;
System.out.println(putUrl);
String newline = "\n";

List listToSign = Lists.newArrayList();
listToSign.add("PUT");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add("application/octet-stream");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add("");
listToSign.add(headerResource);
listToSign.add(urlResource);

String stringToSign = String.join(newline, listToSign);
 Base64 base64 = new Base64();


System.out.println(stringToSign);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(base64.decode(accesskey), "HmacSHA256"));
String authKey = new String(base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));

String authHeader =  "SharedKey " + storageAccount + ":"+ authKey;

System.out.println(authHeader);

InputStreamEntity entity = new InputStreamEntity(
        new ByteArrayInputStream(putData.getBytes(StandardCharsets.UTF_8)), -1,
        ContentType.APPLICATION_OCTET_STREAM);

// set chunked transfer encoding ie. no Content-length
entity.setChunked(true);
HttpPut httpPut = null;
try {

    DefaultHttpClient httpClient =  new DefaultHttpClient();
    httpClient.removeRequestInterceptorByClass(org.apache.http.protocol.RequestContent.class);

    httpPut = new HttpPut(putUrl);
    httpPut.setHeader("Host", storageAccount + ".blob.core.windows.net");
    httpPut.setHeader("Transfer-Encoding","chunked");
    //httpPut.setHeader("Content-Length","0");
    httpPut.setHeader("Content-Type","application/octet-stream");
    httpPut.addHeader("x-ms-blob-type", "BlockBlob");
    httpPut.addHeader("x-ms-date", currentDate);
    httpPut.addHeader("x-ms-version", version);
    httpPut.addHeader("Authorization",authHeader);


    httpPut.setEntity(entity);

    System.out.println("Request Headers");

    for (Header header : httpPut.getAllHeaders()) {
        System.out.println(header.getName() + ":" + header.getValue());
    }
    HttpResponse response = httpClient.execute(httpPut);
    System.out.println(response.getStatusLine());


    for (Header header: response.getAllHeaders()) {
        System.out.println(header.getName()+":"+ header.getValue());
    }
    // Read the contents of an entity and return it as a String.
    String content = EntityUtils.toString(response.getEntity());
    System.out.println(content);

} finally {

    if(httpPut != null ){
        httpPut.releaseConnection();
    }
}

Ответ от сервера

HTTP Error 400. There is an invalid content length or chunk length in the request.

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


  • Вышеупомянутый код работает, если я устанавливаю длину содержимого как часть информации о подписи и заголовке. 10.07.2018
  • AFAIK, это невозможно. Вам нужно будет указать длину содержимого. Однако мне любопытно узнать ваш вариант использования. 10.07.2018
  • Почему бы не использовать пакет SDK для Java службы хранилища Azure вместо прямого вызова REST API? github.com/Azure/azure-storage-java 10.07.2018
  • Вся проблема заключается в отсутствии длины содержимого и использовании azure api, то есть в том, чтобы не обрабатывать пользовательские данные до того, как их можно будет передать в API. Мы уже используем SDK, но теперь требуется направить поток входных данных непосредственно в api. API хранилища GCS позволяет, поэтому это ограничение стало неожиданностью. 10.07.2018

Ответы:


1

Мы можем использовать ByteArrayEntity для получения длины содержимого вместо использования InputStreamEntity

Вот простая демонстрация для вашей справки:

        FileInputStream fileInputStream=null;
        ByteArrayOutputStream bos = null ;
        try {
            fileInputStream=new FileInputStream("D:/Test/Test.txt");
            bos = new ByteArrayOutputStream();
            byte[] bytes=new byte[102400];
            int x=0;
            while ((x=fileInputStream.read(bytes))!= -1){
                bos.write(bytes,0,x);
            }
            byte[] data = bos.toByteArray();

            org.apache.http.entity.ByteArrayEntity byteArrayEntity=new ByteArrayEntity(data);
            int contentLength=data.length;

        } catch (Exception e) {
            e.printStackTrace();
        }

Как сказал выше Чжаосин Лу, для этого мы можем использовать Java SDK, вот демонстрация, которая использует Java SDK для справки:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.microsoft.azure.storage.blob.ListBlobItem;

public class Main {

     public static final String ConnString="DefaultEndpointsProtocol=https;AccountName=xxxxxxxxb;AccountKey=O7xxxx8e86XQSy2vkvSi/x/e9l9FhLqxxxxjkly1DsQPYY5dF2JrAVxxxxo29ZrrGJA==;EndpointSuffix=core.windows.net";
    public static void main(String[] args) {
        // TODO Auto-generated method stub      
        uploadBlob("mycontainer","TechTalk.pptx","E:\\Test\\TechTalk.pptx");
        System.out.println("Success");

    }

    public static void uploadBlob(String containerName, String blobName,String filePath) {
        CloudStorageAccount account = null;
        CloudBlobContainer container = null;
        try {
            account = CloudStorageAccount.parse(ConnString);
            CloudBlobClient client = account.createCloudBlobClient();
            container = client.getContainerReference(containerName);
            container.createIfNotExists();
            CloudBlockBlob cloudBlockBlob = container.getBlockBlobReference(blobName);
            FileInputStream fileinputStream=new FileInputStream(filePath);
            cloudBlockBlob.upload(fileinputStream, fileinputStream.available());
        }catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

Мы можем получить Java SDK по адресу: Java SDK

10.07.2018
  • Спасибо Ли за проверку, но наше требование состоит в том, чтобы использовать api без информации о длине контента. Рассматривайте его как приложение уровня прокси для передачи пользовательских данных в api без промежуточной передачи данных в конце приложения. Кроме того, этим потоком можно будет управлять на лету, следовательно, даже если пользователь передает длину содержимого потока данных, это не будет полезно 10.07.2018
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...