Вопрос или проблема
В настоящее время я работаю над решением на 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
-
Неправильный формат URL или неверная ссылка SAS: Убедитесь, что вы правильно формируете URL для запроса. Ваша переменная
objectName
должна содержать только путь к блобу, без лишних символов. Проверьте, что у вас есть весь необходимый контент в ссылке SAS, включая правильные параметры доступа. -
Неправильно настроенные заголовки: Убедитесь, что вы добавляете заголовки корректно. Ошибка в формировании заголовков может привести к сбросу соединения. Попробуйте использовать
HttpAddRequestHeadersW
без использованияvbCrLf
, так как это может вызвать ошибки. Заголовки должны заканчиваться только на NULL-символе. -
Проблемы с временем ожидания (timeouts): Хотя вы уже установили значения тайм-аутов, попробуйте использовать немного большее значение на случай, если процесс загрузки занимает больше времени. Убедитесь, что использование
InternetSetOptionW
действительно устанавливает таймауты, и они применены к правильному дескриптору. -
Проблемы сети или межсетевого экрана: Убедитесь, что ваше подключение к интернету стабильно, и ваш корпоративный или локальный межсетевой экран не блокирует соединение с 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
Рекомендации
-
Убедитесь в корректности SAS URL: Проверьте, имеет ли предоставленный SAS URL все необходимые разрешения для записи.
-
Проверка сетевых настроек: Если у вас есть корпоративный прокси или VPN, попробуйте отключить его, чтобы проверить, не в нем ли причина сбоя.
-
Обработайте ошибки более подробно: Добавьте больше отладочных сообщений, чтобы понять, на каком этапе происходит ошибка. Используйте
Debug.Print
для вывода каждого этапа, чтобы изолировать место сбоя. -
Логи Azure: Проверьте логи на Azure, чтобы увидеть, была ли попытка подключения и получение дополнительной информации о причине сбоя.
Если после всех предложенных изменения проблема не решится, возможно, имеет смысл попробовать другой подход, например, использовать Azure SDK для VBA или использовать MSXML вместо WinINet для работы с HTTP-запросами.