Hướng dẫn nâng cấp aiohttp 2.x: Phân tích thay đổi lớn ở client và server

Hướng dẫn nâng cấp aiohttp 2.x: Phân tích thay đổi lớn ở client và server

Giới thiệu

aiohttp - framework HTTP đồng bộ/asynchronous hàng đầu trong hệ sinh thái Python đã có nhiều cải tiến quan trọng trong phiên bản 2.x. Bài viết này sẽ phân tích chi tiết các thay đổi này, giúp lập trình viên thực hiện quá trình nâng cấp một cách hiệu quả. Chúng ta sẽ tìm hiểu cụ thể từng thay đổi ở cả hai thành phần client và server.

Thay đổi ở phía client

Tối ưu cơ chế truyền dữ liệu

Mã hóa phân đoạn (chunking)

Phiên bản 2.x loại bỏ hỗ trợ tùy chỉnh kích thước phân đoạn. Người dùng cần tự quản lý việc chia nhỏ luồng dữ liệu. Khi bật chế độ chunked, aiohttp sẽ tự động thêm header "Transfer-encoding: chunked".

Điểm thay đổi chính:

  • Không còn tự động kích hoạt mã hóa phân đoạn dù có header transfer-encoding
  • Phải thiết lập tham số chunked để kích hoạt
  • Không cho phép đồng thời header Transfer-encoding và content-length khi dùng chunked
Nén dữ liệu (compression)

Tính năng nén dữ liệu phải được kích hoạt qua tham số compress:

  • Không cho phép thêm header content-encoding khi nén
  • Nén tự động kích hoạt mã hóa chunked
  • Không thể sử dụng cùng lúc Content-Length khi nén

Tái cấu trúc connector

Các thay đổi quan trọng trong connector:

  1. Mô hình giới hạn kết nối:
  • Trước: giới hạn kết nối theo host
  • Bây giờ:
  • limit điều khiển tổng kết nối đồng thời
  • limit_per_host điều khiển kết nối mỗi host
  • Mặc định không giới hạn host
  1. Phương thức đóng kết nối:
  • BaseConnector.close chuyển thành phương thức thông thường
  1. Thời gian chờ:
  • BaseConnector.conn_timeout di chuyển sang ClientSession

Cải tiến xử lý response

Response object được tái thiết kế hoàn toàn:

  • Không cần gọi release thủ công
  • Kết nối tự động trả về pool sau khi nhận đủ dữ liệu
  • Kết nối bị đóng nếu dữ liệu chưa được đọc hết

Sửa đổi hệ thống exception

Cấu trúc exception được thay đổi lớn:

  1. Giảm loại exception:
  • Chỉ giữ lại exception liên quan đến kết nối và phản hồi server
  • Lỗi code sai tiếp tục dùng exception chuẩn Python
  1. Thêm lỗi nội dung:
  • Có thể gặp ClientPayloadError khi đọc nội dung phản hồi
  1. Điều chỉnh module:
  • Tất cả exception di chuyển từ aiohttp.errors sang aiohttp

Hệ thống payload mới

Hệ thống Payload được giới thiệu để xử lý dữ liệu form:

  1. Thay đổi FormData:
  • FormData.__call__ loại bỏ tham số encoding
  • Trả về Payload instance thay vì iterator/bytes
  • Tự động hỗ trợ các kiểu dữ liệu phổ biến (str, byte, io.IOBase)
  1. Giải pháp thay thế generator:
  • Hỗ trợ generator bị loại bỏ
  • Sử dụng decorator @aiohttp.streamer để upload luồng

Ví dụ:

@aiohttp.streamer
def file_sender(writer, file_path=None):
    with open(file_path, 'rb') as f:
        while chunk := f.read(2**16):
            yield from writer.write(chunk)

async with session.post(url, data=file_sender('large_file')) as resp:
    print(await resp.text())

Các thay đổi khác

  1. Tham số mã hóa:
  • Tham số encoding trong ClientSession.request() đã bị loại bỏ
  • Quyết định mã hóa tại cấp độ Payload
  1. Tham số phiên bản:
  • Tham số version trong ClientSession.request() bị xóa
  • Thiết lập phiên bản qua constructor ClientSession
  1. Hằng số kiểu:
  • aiohttp.MsgType thay bằng aiohttp.WSMsgType
  1. Xử lý URL:
  • ClientResponse.url trả về instance yarl.URL
  • url_obj bị loại bỏ
  1. Kiểm tra trạng thái:
  • ClientResponse.raise_for_status() ném aiohttp.ClientResponseError
  1. Đọc JSON nghiêm ngặt:
  • ClientResponse.json() kiểm tra chặt chẽ content-type
  • Dùng content_type=None để tắt kiểm tra

Thay đổi ở phía server

Tái thiết kế giao thức

Thay đổi lớn để cải thiện hiệu năng và hỗ trợ HTTP pipelining:

  • ServerHttpProtocol bị loại bỏ
  • Gộp chức năng vào RequestHandler
  • Nhiều API cấp thấp bị xóa

Ứng dụng (Application)

  1. Xử lý vòng lặp sự kiện:
  • Tham số loop trong constructor bị loại bỏ
  • Vòng lặp được cấu hình tự động qua run_app
  1. Đường dẫn con:
  • Application.router.add_subapp bị xóa
  • Thay bằng Application.add_subapp
  1. Sự kiện hoàn thành:
  • Application.finished bị xóa
  • Thay bằng Application.cleanup

Request/Response

  1. Xử lý tham số:
  • Thuộc tính GETPOST bị xóa
  • Sử dụng query thay thế GET
  1. Mã hóa phân đoạn:
  • Không còn hỗ trợ tùy chỉnh kích thước phân đoạn
  • Người dùng tự quản lý logic phân đoạn
  1. Hỗ trợ payload:
  • Có thể dùng Payload làm nội dung phản hồi
  • Dùng nội dung phản hồi client làm body cho WebResponse
  1. API gửi file:
  • FileSender bị xóa
  • Thay bằng FileResponse linh hoạt hơn

Ví dụ:

async def handle(request):
    return web.FileResponse('document.txt')

  1. Thuộc tính WebSocket:
  • WebSocketResponse.protocol đổi tên thành ws_protocol
  • Thuộc tính protocol hiện là instance RequestHandler

Lỗi payload request

Thêm exception RequestPayloadError hoạt động tương tự ClientPayloadError để xử lý lỗi đọc payload request.

Hỗ trợ WSGI

  • Loại bỏ hoàn toàn hỗ trợ WSGI
  • Bao gồm worker WSGI cho gunicorn
  • Vẫn giữ worker gunicorn mặc định và uvloop cho web.Application

Gợi ý nâng cấp

  1. Nâng cấp từng bước:
  • Xử lý client trước, server sau
  • Bắt đầu từ các module đơn giản
  1. Kiểm tra trọng tâm:
  • Logic xử lý lỗi
  • Triển khai upload/download
  • Cấu hình pool kết nối
  1. Chiến lược test:
  • Tăng cường test trường hợp biên
  • Tập trung vào tình huống truyền luồng
  1. Tối ưu hiệu năng:
  • Tận dụng tham số giới hạn kết nối mới
  • Kiểm tra sử dụng RAM với tải khác nhau

Bài viết trên đã phân tích chi tiết các thay đổi lớn của aiohttp 2.x. Phiên bản mới cải thiện đáng kể hiệu năng và tính nhất quán của API, xứng đáng để dành thời gian nâng cấp.

Thẻ: aiohttp AsyncIO python http Web Framework

Đăng vào ngày 14 tháng 9 lúc 14:00