
АВС 5 ЛР
.docx
Министерство науки и высшего образования Российской Федерации
Федеральное государственное бюджетное
образовательное учреждение высшего образования
«Уфимский университет науки и технологий»
Институт информатики, математики и робототехники
Отчёт по лабораторной работе № 5
по дисциплине «Архитектура вычислительных систем»
на тему: «Работа с протоколами прикладного уровня. Метод AJAX»
Выполнил:
студент группы ПРО-332б Ихсанова Э. А.
Проверил:
преподаватель Юдинцев Б.С.
Уфа – 2024
Цель работы и задачи
Ознакомиться с теоретической информацией по реализации подхода AJAX.
Изучить код html-страницы, использующей метод AJAX (см. папку с кодом веб-сервера: www/webclient.html). Проверить работу всех HTTP-методов.
Расширить функциональные возможности веб-сервера из лабораторной работы №4 (см. файлы в архиве lab5_Python_ПРИМЕР.zip). При обращении по адресу <адрес_веб_сервера>/posted реализовать обработку всех HTTP-методов, которые использует страница webclient.html:
GET: сформировать ответ с содержимым файла, указанным в поле «Имя_файла», если файла не существует сформировать jsonответ с HTTP-кодом ошибки.
POST: запись данных из поля «Запрос клиента» в файл с уникальным именем (должно быть реализовано в ходе выполнения ЛР№4) и сформировать json-ответ с полями, содержащими код успешного выполнения операции и имя созданного файла.
PUT: заменить файл по имени, указанному в поле «Имя файла». При успешном выполнении сформировать json-ответ с HTTP-кодом 201, если файла не существует, сформировать json-ответ с HTTPкодом ошибки.
DELETE: удалить файл по имени, указанному в поле «Имя файла». При успешном выполнении сформировать json-ответ с HTTPкодом 200, если файла не существует сформировать json-ответ с HTTP-кодом ошибки.
Удалить из javascript-кода страницы инструкцию preventDefault(), проверить выполнение HTTP-операций со страницы. Сделать вывод о том, что поменялось в работе страницы и почему.
Запустить веб-сервер на ВМ. Приложить к отчету скриншоты страницы webclient.html с результатами выполнения каждой операции (консоль разработчика также должна быть открыта)
Ход работы
Основная работа над программой была проведена в целях реализации корректной обработки PUT и DELETE запросов сервером. Функция read_client_request была переработана для корректной работы с AJAX.
def read_client_request(self, req): req_data = req.split('\r\n\r\n') head_data = req_data[0].split('\r\n') if len(head_data) > 0: main_header_data = head_data[0].split(' ') req_type = main_header_data[0] req_path = main_header_data[1] if req_type == 'GET': return self.read_get_request(req_path) elif req_type == 'POST': return self.read_post_request(head_data, req_data[1:]) elif req_type == 'PUT': return self.read_put_request(req_data[1:]) elif req_type == 'DELETE': return self.read_delete_request(req_data[1]) return self.make_http_header(OK, 0)
Так же, помимо добавления обработки PUT и DELETE запросов были переработаны и функции GET, POST. Полный код будет приведен далее в листинге conthread.py
Работа на странице webclient.html:
Ниже не скриншоте приведена работа с AJAX-ми. Во вкладке ответ сервера можно увидеть полную историю выполнения операций с файлом.
Рисунок 1 – webclient
Если удалить из кода страницы preventDefault(), то страница начнет автоматически обновляться при нажатии на любую из кнопок, что сделает работу невозможной.
Вывод:
В ходе лабораторной работы была реализована обработка PUT и DELETE запросов, была переработана часть кода для работы с AJAX-ми. Был изучен AJAX, как метод в целом.
Листинг conthread.py
from threading import Thread import uuid import json import sys import os ROOT_DIR = "www" POST_DIR = "posted" POST_MAX_SIZE = 1024 * 1024 * 2 KEEP_ALIVE = 10 OK = "200 OK" NOT_FOUND = "404 Not Found" BAD_REQUEST = "400 Bad Request" SERVER_ERROR = "500 Internal Server Error" FILE_CREATED = "201 Created" DELETED = "200 Bye Bye" MIME_TYPES = [ "text/xml", "application/json", "application/xml", ] class HTTPConnectionThread(Thread): def __init__(self, conn, addr): Thread.__init__(self) self.connection = conn self.address = addr self._root_path = os.path.join(os.path.abspath(os.getcwd()), ROOT_DIR) def run(self): request = "" while request is not None: try: request = self.connection.recv(POST_MAX_SIZE) data = request.decode("utf-8") if data == '': print("Keep-alive timeout.") break response = self.read_client_request(data) self.connection.send(response.encode("utf-8")) except Exception as error: print("HTTP Connection error:\n", error) break self.connection.close() def make_http_header(self, code, length, content_type='text/html'): header = f'HTTP/1.1 {code}\r\n' \ f'Server: python_lab_4\r\n' \ f'Content-Type: {content_type}; charset=utf-8\r\n' \ f'Content-Length: {length}\r\n' \ f'Keep-Alive: timeout={KEEP_ALIVE}, max=100\r\n' \ f'Connection: Keep-Alive\r\n\r\n' return header def get_content_page(self, path): content = "" if path != "/index.html" and not (path.endswith(".html")): full_path = self._root_path + "/" + POST_DIR + path else: full_path = self._root_path + path if sys.platform.startswith('win'): full_path = full_path.replace("/", "\\") content_type = self.get_content_type(full_path) if os.path.isfile(full_path): if full_path.endswith('.json'): with open(full_path, "r", encoding="utf-8") as json_file: content = json.load(json_file) content = json.dumps(content) else: with open(full_path, "r", encoding="utf-8") as page: content = page.read() else: return self.make_http_header(NOT_FOUND, len("File not found " + full_path)) + "File not found " + full_path return self.make_http_header(OK, len(content.encode("utf-8")), content_type=content_type) + content def get_content_type(self, path): if path.endswith(".html"): return 'text/html' elif path.endswith(".xml"): return 'text/xml' elif path.endswith(".json"): return "application/json" def read_client_request(self, req): req_data = req.split('\r\n\r\n') head_data = req_data[0].split('\r\n') if len(head_data) > 0: main_header_data = head_data[0].split(' ') req_type = main_header_data[0] req_path = main_header_data[1] if req_type == 'GET': return self.read_get_request(req_path) elif req_type == 'POST': return self.read_post_request(head_data, req_data[1:]) elif req_type == 'PUT': return self.read_put_request(req_data[1:]) elif req_type == 'DELETE': return self.read_delete_request(req_data[1]) return self.make_http_header(OK, 0) def read_get_request(self, path): if path == "/": path = "/index.html" return self.get_content_page(path) def read_put_request(self, data): data_dict = json.loads(data[0]) filename = data_dict['filename'] filedata = data_dict['filedata'] filedata = filedata.replace('\\"', '"') filedata = filedata.replace('\\', '') file_path = os.path.join(ROOT_DIR, POST_DIR, filename) if (os.path.isfile(file_path)): with open(file_path, 'w', encoding='utf-8') as f: data = json.loads(filedata) json.dump(data, f, indent=None) return self.make_http_header(FILE_CREATED, len(f"File updated as {filename}")) + f"File updated as {filename}" else: full_path = self._root_path + "/" + POST_DIR + filename return self.make_http_header(NOT_FOUND, len("File not found " + full_path)) + "File not found " + full_path def read_post_request(self, head_data, data): filedata = data[0] content_type = None for header in head_data[1:]: if header.startswith("Content-Type:"): content_type = header.split(": ")[1].strip() break if content_type in MIME_TYPES and content_type: file_ext = content_type.split('/')[1] file_name = str(uuid.uuid4()) + '.' + file_ext file_path = os.path.join(ROOT_DIR, POST_DIR, file_name) with open(file_path, 'w', encoding='utf-8') as f: f.write(filedata) return self.make_http_header(OK, len("File saved as: " + file_name), "text/html") + "File saved as: " + file_name else: return self.make_http_header(BAD_REQUEST, len("Unsupported content type: " + content_type), "text/html") + "Unsupported content type: " + content_type def read_delete_request(self, filename): filename = filename.split(":")[-1].strip().rstrip('}').replace('"', '').replace("'", '') full_path = self._root_path + "/" + POST_DIR + '/' + filename if (os.path.isfile(full_path)): os.remove(full_path) return self.make_http_header(OK, len("File deleted successfully")) + "File deleted successfully" else: return self.make_http_header(NOT_FOUND, len("File not found " + full_path)) + "File not found " + full_path