Проблемы с загрузкой файлов в Azure Blob с использованием API WinINet в VBA (Ошибка 12031)

Вопрос или проблема

В настоящее время я работаю над решением на VBA, которое загружает файлы в Azure Blob Storage с использованием API WinINet в VBA. Я столкнулся с несколькими проблемами, в частности с функцией HttpSendRequestW, которая возвращает код ошибки 12031 (ERROR_INTERNET_CONNECTION_RESET). Несмотря на добавление соответствующих заголовков и корректную обработку данных файла, запрос завершается неудачей. Обзор кода:

Открытие интернет-соединения с использованием InternetOpenW.
Подключение к Azure Blob Storage с помощью InternetConnectW.
Открытие PUT-запроса с использованием HttpOpenRequestW.
Добавление необходимых заголовков (например, x-ms-blob-type: BlockBlob и Content-Length).
Отправка HTTP-запроса с помощью HttpSendRequestW, включая данные файла из локального файла.

Проблема:

Код выполняется без ошибок до момента отправки запроса. Однако вызов HttpSendRequestW завершается с ошибкой 12031, которая, согласно документации Microsoft, относится к “сбросу соединения”. Я не уверен, почему это происходит, поскольку настройка соединения кажется правильной.

Шаги отладки:

Я подтвердил, что заголовки добавлены корректно.
Размер файла вычисляется правильно.
Я установил различные таймауты с помощью InternetSetOptionW, чтобы избежать преждевременных проблем с таймаутом.
Буфер файла и другие параметры кажутся в порядке.

Ключевая проблема:

Код ошибки: 12031 (Соединение сброшено удаленной стороной) возникает во время вызова HttpSendRequestW.
Таймауты: я установил таймауты соединения, отправки и получения на 60 секунд с помощью InternetSetOptionW, но проблема сохраняется.

Полный код:

Public Sub UploadFileToAzureBlob2(ByVal filePath As String, ByVal Url As String, ByVal sasUrl As String)
    Dim hInternet As Long
    Dim hConnect As Long
    Dim hRequest As Long
    Dim Buffer() As Byte
    Dim FileHandle As Integer
    Dim dwFileSize As Long

    ' Открыть интернет-соединение
    hInternet = InternetOpenW(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0)
    If hInternet = 0 Then
        Debug.Print "Ошибка при открытии интернета: " & ERR.LastDllError
        Exit Sub
    End If

    ' Извлечение имени сервера из URL
    Dim serverName As String
    serverName = Mid(Url, InStr(Url, "//") + 2)
    Debug.Print "Имя сервера: " & serverName

    ' Подключение к URL Azure Blob Storage
    hConnect = InternetConnectW(hInternet, StrPtr(serverName), _
                                INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0)
    If hConnect = 0 Then
        Debug.Print "Ошибка подключения к URL: " & ERR.LastDllError
        InternetCloseHandle hInternet
        Exit Sub
    End If

    ' Извлечение имени объекта (контейнер + имя блоба + SAS токен)
    Dim objectName As String
    objectName = Mid(sasUrl, Len(Url) + 1)
    Debug.Print "Имя объекта: " & objectName

    ' Открыть HTTP PUT-запрос
    hRequest = HttpOpenRequestW(hConnect, StrPtr("PUT"), StrPtr(objectName), 0, 0, 0, INTERNET_FLAG_SECURE Or INTERNET_FLAG_NO_CACHE_WRITE, 0)
    If hRequest = 0 Then
        Debug.Print "Ошибка при открытии запроса: " & ERR.LastDllError
        InternetCloseHandle hConnect
        InternetCloseHandle hInternet
        Exit Sub
    End If

    ' Чтение файла в буфер
    FileHandle = FreeFile
    Open filePath For Binary Access Read As FileHandle
    dwFileSize = LOF(FileHandle)
    If dwFileSize = 0 Then
        Debug.Print "Ошибка: Размер файла равен нулю"
        Close FileHandle
        InternetCloseHandle hRequest
        InternetCloseHandle hConnect
        InternetCloseHandle hInternet
        Exit Sub
    End If
    ReDim Buffer(dwFileSize - 1)
    Get FileHandle, , Buffer
    Close FileHandle

    ' Добавление заголовков
    If HttpAddRequestHeadersW(hRequest, StrPtr("x-ms-blob-type: BlockBlob" & vbCrLf), _
        ByVal Len("x-ms-blob-type: BlockBlob" & vbCrLf), 0) = 0 Then
        Debug.Print "Ошибка при добавлении заголовка типа блоба: " & ERR.LastDllError
        InternetCloseHandle hRequest
        InternetCloseHandle hConnect
        InternetCloseHandle hInternet
        Exit Sub
    End If

    ' Создание строки заголовка Content-Length
    Dim contentLength As String
    contentLength = "Content-Length: " & dwFileSize & vbCrLf

    ' Добавление заголовка Content-Length
    If HttpAddRequestHeadersW(hRequest, StrPtr(contentLength), _
        ByVal Len(contentLength) - 2, 0) = 0 Then ' Вычитаем 2 для CRLF
        Debug.Print "Ошибка при добавлении заголовка длины содержимого: " & ERR.LastDllError
        InternetCloseHandle hRequest
        InternetCloseHandle hConnect
        InternetCloseHandle hInternet
        Exit Sub
    End If

    ' Установка таймаутов
    Dim TIMEOUT_VALUE As Long
    TIMEOUT_VALUE = 60000 ' Таймаут 60 секунд
    Call InternetSetOptionW(hInternet, INTERNET_OPTION_CONNECT_TIMEOUT, VarPtr(TIMEOUT_VALUE), 4)
    Call InternetSetOptionW(hInternet, INTERNET_OPTION_SEND_TIMEOUT, VarPtr(TIMEOUT_VALUE), 4)
    Call InternetSetOptionW(hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, VarPtr(TIMEOUT_VALUE), 4)

    ' Отправка HTTP-запроса с данными файла
    If HttpSendRequestW(hRequest, 0, 0, VarPtr(Buffer(0)), dwFileSize) = 0 Then
        Debug.Print "Ошибка при отправке запроса: " & ERR.LastDllError
        Exit Sub
    Else
        Debug.Print "Файл успешно загружен!"
    End If

    ' Закрытие дескрипторов
    InternetCloseHandle hRequest
    InternetCloseHandle hConnect
    InternetCloseHandle hInternet
    Debug.Print "Загрузка завершена успешно!"
End Sub

Ответ или решение

Ваша проблема с загрузкой файлов в Azure Blob Storage через WinINet API в VBA и с ошибкой 12031 (ERROR_INTERNET_CONNECTION_RESET) может быть вызвана несколькими моментами. Давайте рассмотрим ваш код и возможные решения.

Возможные причины ошибки 12031

  1. Неправильный формат URL или неверная ссылка SAS: Убедитесь, что вы правильно формируете URL для запроса. Ваша переменная objectName должна содержать только путь к блобу, без лишних символов. Проверьте, что у вас есть весь необходимый контент в ссылке SAS, включая правильные параметры доступа.

  2. Неправильно настроенные заголовки: Убедитесь, что вы добавляете заголовки корректно. Ошибка в формировании заголовков может привести к сбросу соединения. Попробуйте использовать HttpAddRequestHeadersW без использования vbCrLf, так как это может вызвать ошибки. Заголовки должны заканчиваться только на NULL-символе.

  3. Проблемы с временем ожидания (timeouts): Хотя вы уже установили значения тайм-аутов, попробуйте использовать немного большее значение на случай, если процесс загрузки занимает больше времени. Убедитесь, что использование InternetSetOptionW действительно устанавливает таймауты, и они применены к правильному дескриптору.

  4. Проблемы сети или межсетевого экрана: Убедитесь, что ваше подключение к интернету стабильно, и ваш корпоративный или локальный межсетевой экран не блокирует соединение с Azure.

Изменения в вашем коде

Ниже приведены некоторые изменения, которые могут помочь вам решить вашу проблему:

' Заголовки без vbCrLf
If HttpAddRequestHeadersW(hRequest, StrPtr("x-ms-blob-type: BlockBlob"), ByVal Len("x-ms-blob-type: BlockBlob"), HTTP_ADDREQ_FLAG_ADD) = 0 Then
    Debug.Print "Error adding blob type header: " & ERR.LastDllError
    InternetCloseHandle hRequest
    InternetCloseHandle hConnect
    InternetCloseHandle hInternet
    Exit Sub
End If

' Создание заголовка Content-Length без CRLF
If HttpAddRequestHeadersW(hRequest, StrPtr("Content-Length: " & dwFileSize), ByVal Len("Content-Length: " & dwFileSize), HTTP_ADDREQ_FLAG_ADD) = 0 Then
    Debug.Print "Error adding content length header: " & ERR.LastDllError
    InternetCloseHandle hRequest
    InternetCloseHandle hConnect
    InternetCloseHandle hInternet
    Exit Sub
End If

Рекомендации

  1. Убедитесь в корректности SAS URL: Проверьте, имеет ли предоставленный SAS URL все необходимые разрешения для записи.

  2. Проверка сетевых настроек: Если у вас есть корпоративный прокси или VPN, попробуйте отключить его, чтобы проверить, не в нем ли причина сбоя.

  3. Обработайте ошибки более подробно: Добавьте больше отладочных сообщений, чтобы понять, на каком этапе происходит ошибка. Используйте Debug.Print для вывода каждого этапа, чтобы изолировать место сбоя.

  4. Логи Azure: Проверьте логи на Azure, чтобы увидеть, была ли попытка подключения и получение дополнительной информации о причине сбоя.

Если после всех предложенных изменения проблема не решится, возможно, имеет смысл попробовать другой подход, например, использовать Azure SDK для VBA или использовать MSXML вместо WinINet для работы с HTTP-запросами.

Оцените материал
Добавить комментарий

Капча загружается...