Как использовать REST API для получения свойств файла для хранилища файлов Azure с помощью Python

Я пытаюсь создать скрипт Python, который будет использовать как Python SDK для Azure, так и REST API, чтобы извлекать информацию для файлов в моей учетной записи хранилища файлов Azure.

Я использую SDK для доступа к файлам в хранилище и получения имен. Затем, используя имя, я хочу иметь возможность вызова REST API для получения свойств файла, в частности свойства Last-Modified. Я пытаюсь получить доступ к последнему измененному свойству с помощью SDK, но по какой-то причине он всегда возвращает None.

Я хочу использовать дату последнего изменения, чтобы определить, прошло ли более 24 часов, и если да, то я хочу удалить файл. Я не уверен, можно ли установить какое-то свойство автоматического удаления после определенного периода в файле, когда я впервые создаю и загружаю его в лазурь. Если есть, то это все равно решит мои проблемы.

Я разместил код, который я использую ниже. Когда я пытаюсь сделать HTTP-запрос, я получаю сообщение об ошибке «Серверу не удалось аутентифицировать запрос. Убедитесь, что значение заголовка авторизации сформировано правильно, включая подпись».

    import datetime
    import requests
    import json
    import base64
    import hmac
    import hashlib
    import urllib
    from azure.storage.file import *

StorageAccountConnectionString = ""
fileshareName = "testFileShare"
storage_account_name = "testStorage"
storage_account_key = ""
api_version = "2018-03-28"

        file_service = FileService(connection_string=StorageAccountConnectionString)
    listOfStateDirectories = file_service.list_directories_and_files(fileshareName)

    for state_directory in listOfStateDirectories:
        print("Cleaning up State Directory: " + state_directory.name)
        if(isinstance(state_directory, Directory)):
            listOfBridgeDirectories = file_service.list_directories_and_files(fileshareName, state_directory.name)
            for bridge_directory in listOfBridgeDirectories:
                if(isinstance(bridge_directory, Directory)):
                    print("Cleaning up Bridge Directory: " + bridge_directory.name)
                    path_to_bridge_directory = state_directory.name + "/" + bridge_directory.name
                    listOfFilesAndFolders = file_service.list_directories_and_files(fileshareName, path_to_bridge_directory)

                for file_or_folder in listOfFilesAndFolders:
                    if isinstance(file_or_folder, File):
                        name_of_file = file_or_folder.name

                        # Get the time of the current request
                        request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')

                        string_to_append_to_url = fileshareName + '/' + path_to_bridge_directory + '/' + name_of_file
                        # Parse the url to make sure everything is good
                        # string_to_append_to_url = urllib.parse.quote(string_to_append_to_url)

                        string_params = {
                            'verb': 'HEAD',
                            'Content-Encoding': '',
                            'Content-Language': '',
                            'Content-Length': '',
                            'Content-MD5': '',
                            'Content-Type': '',
                            'Date': '',
                            'If-Modified-Since': '',
                            'If-Match': '',
                            'If-None-Match': '',
                            'If-Unmodified-Since': '',
                            'Range': '',
                            'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version + '\n',
                            'CanonicalizedResource': '/' + storage_account_name + '/' + string_to_append_to_url
                        }

                        string_to_sign = (string_params['verb'] + '\n'
                                          + string_params['Content-Encoding'] + '\n'
                                          + string_params['Content-Language'] + '\n'
                                          + string_params['Content-Length'] + '\n'
                                          + string_params['Content-MD5'] + '\n'
                                          + string_params['Content-Type'] + '\n'
                                          + string_params['Date'] + '\n'
                                          + string_params['If-Modified-Since'] + '\n'
                                          + string_params['If-Match'] + '\n'
                                          + string_params['If-None-Match'] + '\n'
                                          + string_params['If-Unmodified-Since'] + '\n'
                                          + string_params['Range'] + '\n'
                                          + string_params['CanonicalizedHeaders']
                                          + string_params['CanonicalizedResource'])

                        signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()

                        headers = {
                            'x-ms-date': request_time,
                            'x-ms-version': api_version,
                            'Authorization': ('SharedKey ' + storage_account_name + ':' + signed_string)
                        }

                        url = ('https://' + storage_account_name + '.file.core.windows.net/' + string_to_append_to_url)
                        print(url)


                        r = requests.get(url, headers=headers)
                        print(r.content)

ПРИМЕЧАНИЕ. В некоторых каталогах будут пробелы, поэтому я не уверен, влияет ли это на вызов REST API, поскольку в URL-адресе также будут пробелы. Если это действительно повлияет на это, то как мне получить доступ к тем файлам, URL-адреса которых будут содержать пробелы?


person alihasan    schedule 28.01.2019    source источник


Ответы (1)


Я пытаюсь получить доступ к последнему измененному свойству с помощью SDK, но по какой-то причине он всегда возвращает None.

Не все SDK API и REST API возвращают свойство Last-Modified в заголовках ответа, включая REST API List Directories and Files и Python SDK API list_directories_and_files.

Я попытался воспроизвести вашу проблему с помощью SDK, как показано ниже.

generator = file_service.list_directories_and_files(share_name, directory_name)
for file_or_dir in generator:
    if isinstance(file_or_dir, File):
        print(file_or_dir.name, file_or_dir.properties.last_modified)

Из-за того, что метод list_directories_and_files не возвращает никаких свойств в объекте File, поэтому значение file_or_dir.properties.last_modified кода выше равно None.

REST API Get File, Get File Properties, Get File Metadata и API Python SDK get_file_properties, get_file_metadata вернет свойство Last-Modified в заголовках ответа, поэтому для изменения кода, как показано ниже, на получите свойство last_modified, чтобы оно заработало.

generator = file_service.list_directories_and_files(share_name, directory_name)
for file_or_dir in generator:
    if isinstance(file_or_dir, File):
        file_name = file_or_dir.name
        file = file_service.get_file_properties(share_name, directory_name, file_name, timeout=None, snapshot=None)
        print(file_or_dir.name, file.properties.last_modified)

Конечно, вызывать REST API — это то же самое, что использовать SDK API. Однако при построении строки подписи SAS легко ошибиться, и это не удобно для чтения кода.

person Peter Pan    schedule 29.01.2019
comment
Спасибо Питер! Да, я понял, что при использовании объекта File операции со списком последнее измененное значение всегда равно None. Но с помощью get_file_properties класса файловой службы это значение доступно. Спасибо за предложение. - person alihasan; 29.01.2019
comment
@alihasan Не могли бы вы пометить это как ответ, если это сработает для вас? - person Peter Pan; 01.02.2019