Middleware
Starlette berisi beberapa kelas middleware untuk menambahkan perilaku yang berlaku untuk seluruh aplikasi. Ini diimplementasikan sebagai kelas middleware ASGI standar dan dapat diterapkan pada Starlette atau aplikasi ASGI lainnya.
Gunakan peralatan tengah
Kelas aplikasi Starlette memungkinkan Anda memasukkan middleware ASGI dengan cara yang memastikan selalu dibungkus oleh penangan pengecualian.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.htpsredirect impor HTTPSRedirectMiddleware
Dari starlette.middleware.trustedhost impor TrustedHostMiddleware
Rute =...
# Pastikan bahwa semua permintaan termasuk example.com 'atau
# '*. example.com' host header, dan ketat menegakkan http-hanya akses.
Peralatan Tengah = [
Peralatan Tengah (
TrustedHostMiddleware,
diperbolehkan _ hosts = ['example.com', '*. example.com'],
),
Middleware (HTTPSRedirectMiddleware)
]
App = Starlette (rute = rute, middleware=middleware)
Secara default, setiap aplikasi Starlette secara otomatis mencakup dua buah middleware:
ServerErrorMiddleware- Memastikan bahwa pengecualian aplikasi dapat mengembalikan 500 halaman kustom, atau menampilkan informasi jejak untuk aplikasi dalam mode DEBUG. Ini selalu merupakan lapisan middleware terluar.ExceptionMiddleware- Tambahkan penangan pengecualian sehingga jenis pengecualian tertentu yang diharapkan dapat dikaitkan dengan fungsi penangan. Misalnya, menaikkan dalam titik akhirHTTPException(status_code=404)Halaman 404 kustom pada akhirnya akan dirender.
Middleware dievaluasi dari atas ke bawah, jadi dalam aplikasi sampel kami, aliran eksekusi akan terlihat seperti ini:
- peralatan tengah
ServerErrorMiddlewareTrustedHostMiddlewareHTTPSRedirectMiddlewareExceptionMiddleware
- rute
- titik akhir
Implementasi middleware berikut tersedia dalam paket Starlette:
Peralatan Tengah CORS
Tambahkan header CORS yang sesuai ke respons keluar untuk memungkinkan permintaan lintas asal dari browser.
Parameter default yang digunakan oleh implementasi CORSMiddleware dibatasi secara default, jadi Anda harus secara eksplisit mengaktifkan sumber, metode, atau header tertentu sehingga browser diizinkan untuk menggunakannya dalam konteks lintas-asal.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
CORSMiddleware impor dari starlette.middleware.cors
Rute =...
Peralatan Tengah = [
Middleware (CORSMiddleware, izinkan _ origins = ['*'])
]
App = Starlette (rute = rute, middleware=middleware)
Argumen berikut didukung:
allow_origins- Daftar sumber yang harus diizinkan untuk membuat permintaan lintas asal. Misalnya['https://example.org', 'https://www.example.org']. Anda dapat menggunakan['*']untuk mengizinkan sumber apa pun.allow_origin_regex- String ekspresi reguler yang cocok dengan sumber yang harus diizinkan untuk membuat permintaan lintas asal. Misalnya:'https://.*\.example\.org'.allow_methods- Daftar metode HTTP yang harus diizinkan untuk permintaan lintas asal. Defaultnya adalah['GET']. Anda dapat menggunakan['*']untuk mengizinkan semua metode standar.allow_headers- Daftar header permintaan HTTP yang harus didukung untuk permintaan lintas asal. Default adalah[]. Anda dapat menggunakan['*']untuk mengizinkan semua header. Untuk permintaan CORS, headerAccept,Accept-Language,Content-Language, danContent-Typeselalu diperbolehkan.allow_credentials- menunjukkan bahwa cookie untuk permintaan lintas asal harus didukung. Defaultnya adalahFalse. Juga, untuk memungkinkan kredensial,allow_origins,allow_methods, danallow_headerstidak dapat diatur ke['*'], semuanya harus ditentukan secara eksplisit.expose_headers- Menunjukkan header respons apa pun yang harus dapat diakses ke browser. Default adalah[].max_age- Mengatur waktu maksimum dalam hitungan detik bagi browser untuk menyimpan respons CORS. Defaultnya ke600.
Middleware menanggapi dua jenis permintaan HTTP tertentu...
Berbagi Sumber Daya Lintas Asal (CORS) Periksa Permintaan
Ini adalah permintaan OPTIONS dengan header Origin dan Access-Control-Request-Method. Dalam hal ini, middleware akan mencegat permintaan masuk dan merespons dengan header CORS yang sesuai, serta respons 200 atau 400 untuk tujuan informasi.
permintaan sederhana
Setiap permintaan dengan header Origin. Dalam hal ini, middleware akan melewati permintaan seperti biasa, tetapi akan menyertakan header CORS yang sesuai sebagai tanggapan.
percakapan middleware
Tambahkan sesi HTTP berdasarkan cookie tanda tangan. Informasi sesi dapat dibaca tetapi tidak dapat dimodifikasi.
Gunakan antarmuka kamus request.session untuk mengakses atau memodifikasi data sesi.
Argumen berikut didukung:
secret_key- Harus string acak.session_cookieNilai default adalah "percakapan."max_age- waktu kedaluwarsa sesi dalam hitungan detik. Default adalah 2 minggu. Jika disetel keNone, periode valid cookie akan sama dengan durasi sesi browser. Bendera*same_site- SameSite mencegah browser mengirim cookie sesi selama permintaan lintas situs. Defaultnya adalah'lax'.path- Path ditetapkan untuk cookie sesi. Default adalah'/'.https_only- Menunjukkan bahwa bendera keamanan harus disetel (hanya untuk digunakan dengan HTTPS). Default adalahFalse...-
domain- Domain cookie digunakan untuk berbagi cookie di antara subdomain atau di seluruh domain. Peramban mengatur domain secara default ke host yang sama tempat cookie disetel, tidak termasuk subdomain (referensi).Starlette.application diimpor dari Starlette Impor Middleware dari starlette.middleware Dari starlette.middleware.session impor SessionMiddleware
Rute =...
Peralatan Tengah = [ Middleware (SessionMiddleware, secret _ key =..., https _ only = Benar) ]
App = Starlette (rute = rute, middleware=middleware)
Alat tengah redirect HTTPS
Mandat bahwa semua permintaan yang masuk harus https atau wss. Setiap permintaan masuk ke http atau ws akan dialihkan ke skema keamanan.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.htpsredirect impor HTTPSRedirectMiddleware
Rute =...
Peralatan Tengah = [
Middleware (HTTPSRedirectMiddleware)
]
App = Starlette (rute = rute, middleware=middleware)
Tidak ada opsi konfigurasi untuk kelas middleware ini.
Middleware Tuan Rumah Terpercaya
Paksa semua permintaan yang masuk untuk memiliki set header Host yang benar untuk melindungi dari serangan header host HTTP.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.trustedhost impor TrustedHostMiddleware
Rute =...
Peralatan Tengah = [
Middleware (TrustedHostMiddleware, diperbolehkan _ hosts = ['example.com', '*. example.com'])
]
App = Starlette (rute = rute, middleware=middleware)
Argumen berikut didukung:
allowed_hosts- Daftar domain yang harus diizinkan sebagai nama host. Domain kartu liar seperti*.example.comdapat digunakan untuk mencocokkan subdomain. Untuk mengizinkan nama host apa pun, gunakanallowed_hosts=["*"]atau hilangkan middleware.www_redirect- Jika diatur ke True, permintaan untuk versi non-www dari host yang diizinkan akan dialihkan ke rekan-rekan www mereka. Default adalahTrue.
Jika permintaan masuk tidak divalidasi dengan benar, tanggapan 400 akan di kirim.
Peralatan Tengah GZip
Menangani respon GZip untuk setiap permintaan yang mengandung "gzip" di header Accept-Encoding.
Middleware akan menangani respons standar dan streaming.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.gzip impor GZipMiddleware
Rute =...
Peralatan Tengah = [
Middleware (GZipMiddleware, minimum _ size = 1000, tingkat kompresi = 9)
]
App = Starlette (rute = rute, middleware=middleware)
Argumen berikut didukung:
minimum_size- Jangan GZip untuk tanggapan yang lebih kecil dari ukuran byte minimum ini. Defaultnya adalah500.compresslevel- digunakan selama kompresi GZip. Ini adalah bilangan bulat dari 1 hingga 9. Nilai default adalah9. Semakin rendah nilainya, semakin cepat kompresannya, tetapi semakin besar ukuran file; semakin tinggi nilainya, semakin lambat kompresannya, tetapi semakin kecil ukuran file.
Middleware tidak merespons GZip yang telah mengatur Content-Encoding untuk mencegahnya dikodekan dua kali.
Perangkat tengah BaseHTTP
Kelas abstrak yang memungkinkan Anda menulis middleware ASGI untuk antarmuka permintaan / respons.
penggunaan
Untuk menerapkan kelas middleware menggunakan BaseHTTPMiddleware, Anda harus mengesampingkan metode async def dispatch(request, call_next).
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.base impor BaseHTTPMiddleware
Kelas CustomHeaderMiddleware (BaseHTTPMiddleware):
Aync def pengiriman (sendiri, permintaan, panggilan _ berikutnya):
Tanggapan = tunggu panggil _ next (permintaan)
Tanggap.header ['Custom'] = 'Examplede'
Respon kembali
Rute =...
Peralatan Tengah = [
Middleware (CustomHeaderMiddleware)
]
App = Starlette (rute = rute, middleware=middleware)
Jika Anda ingin menyediakan opsi konfigurasi untuk kelas middleware, Anda harus mengesampingkan metode __init__ untuk memastikan bahwa argumen pertama adalah app dan argumen yang tersisa adalah argumen kata kunci opsional. Jika ya, pastikan untuk mengatur properti app pada instance.
Kelas CustomHeaderMiddleware (BaseHTTPMiddleware):
Def _ _ init _ _ (diri, aplikasi, header _ value = 'Contoh'):
Super (). _ _ init _ _ (aplikasi)
Nilai _ header = nilai header
Aync def pengiriman (sendiri, permintaan, panggilan _ berikutnya):
Tanggapan = tunggu panggil _ next (permintaan)
Tanggap.header ['Custom'] = self.header _ value
Respon kembali
Peralatan Tengah = [
Middleware (CustomHeaderMiddleware, header _ value = 'Disesuaikan')
]
App = Starlette (rute = rute, middleware=middleware)
Kelas Middleware tidak boleh mengubah status mereka di luar metode __init__. Sebagai gantinya, Anda harus meninggalkan negara bagian mana pun lokal dengan metode dispatch, atau meneruskannya secara eksplisit, daripada mengubah keadaan contoh middleware.
batasan
Saat ini,BaseHTTPMiddleware memiliki beberapa keterbatasan yang diketahui:
- Menggunakan
BaseHTTPMiddlewareakan mencegah perubahancontextlib.ContextVarmenyebar ke atas. Artinya, jika Anda menetapkan nilai untukContextVardi titik akhir dan mencoba membacanya dari estafet, Anda akan menemukan bahwa nilainya berbeda dari apa yang Anda tetapkan di titik akhir (lihat tes ini sebagai contoh perilaku ini).
Untuk mengatasi keterbatasan ini, gunakan middleware ASGI murni, seperti yang ditunjukkan di bawah ini.
Middleware ASGI Murni
Spesifikasi ASGI memungkinkan untuk mengimplementasikan middleware ASGI secara langsung menggunakan antarmuka ASGI, sebagai serangkaian aplikasi ASGI, memanggil yang berikutnya secara bergantian. Faktanya, ini adalah bagaimana kelas middleware yang di kirim dengan Starlette diimplementasikan.
Pendekatan tingkat yang lebih rendah ini memberikan kontrol yang lebih besar atas perilaku dan meningkatkan interoperabilitas di seluruh kerangka kerja dan server. Ini juga mengatasi keterbatasan BaseHTTPMiddleware.
Menulis middleware ASGI murni
Cara paling umum untuk membuat middleware ASGI adalah dengan menggunakan kelas.
Kelas ASGIMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Menunggu self.app (lingkup, menerima, mengirim)
Middleware di atas adalah middleware ASGI paling dasar. Dibutuhkan aplikasi ASGI induk sebagai parameter dalam konstruktornya dan mengimplementasikan metode async __call__ yang memanggil aplikasi induk.
Beberapa implementasi, seperti asgi-cors, menggunakan gaya alternatif, menggunakan fungsi:
Alat fungsi impor
Pasti asgi _ middleware ():
Def asgi _ dekorator (aplikasi):
@ fungtools.wraps (aplikasi)
Aync def dibungkus _ app (lingkup, terima, kirim):
Await aplikasi (lingkup, terima, kirim)
Kembali dibungkus _ app
Kembali asgi _ dekorator
Namun, middleware ASGI harus menjadi objek yang dapat dipanggil yang menerima tiga parameter:scope,receive, dan send.
scopeadalah kamus yang menyimpan informasi tentang koneksi, di manascope["type"]mungkin:"http": Digunakan untuk permintaan HTTP."websocket": Digunakan untuk koneksi WebSocket."lifespan": Untuk pesan siklus hidup ASGI.
receivedansendDapat digunakan untuk bertukar pesan acara ASGI dengan server ASGI - lebih lanjut tentang ini di bawah ini. Jenis dan konten pesan ini tergantung pada jenis ruang lingkup. Pelajari lebih lanjut dalam spesifikasi ASGI.
Menggunakan middleware ASGI murni
Middleware ASGI murni dapat digunakan sama seperti middleware lainnya.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari middleware impor ASGIMiddleware
Rute =...
Peralatan Tengah = [
Middleware (ASGIMiddleware),
]
Aplikasi = Starlette (..., middleware=middleware)
Lihat juga Menggunakan Middleware.
ketik anotasi
Ada dua cara untuk memberi anotasi pada middleware: menggunakan Starlette itu sendiri atau asgiref.
-
Menggunakan Starlette: Cocok untuk kasus penggunaan yang paling umum.
Dari starlette.type import ASGIApp, Pesan, Lingkup, Terima, Kirim
Kelas ASGIMiddleware: Def _ _ init _ _ (sendiri, aplikasi: ASGIApp) - > Tidak ada: self.app = aplikasi
Sinkronisasi def _ _ call _ _ (diri, lingkup: Lingkup, terima: Terima, kirim: Kirim) - > Tidak ada: Jika lingkup ["ketik"]! = "http": Kembali menunggu self.app (lingkup, menerima, mengirim) Async def send _ wrapper (pesan: Pesan) - > Tidak ada: #... Lakukan sesuatu Menunggu pengiriman (pesan) Menunggu self.app (lingkup, menerima, mengirim _ wrapper) -
menggunakan
asgiref: untuk mencapai petunjuk tipe yang lebih ketat.Dari asgiref.typing import ASGI3Application, ASGIReceiveCallable, ASGISendCallable, Scope Dari asgiref.typing impor ASGIReceiveEvent, ASGISendEvent
Kelas ASGIMiddleware: Def _ _ init _ _ (sendiri, aplikasi: ASGI3Aplikasi) - > Tidak ada: self.app = aplikasi
Async def _ _ call _ _ (diri, lingkup: Lingkup, terima: ASGIReceiveCallable, kirim: ASGISendCallable) - > Tidak ada: Jika lingkup ["ketik"]! = "http": Menunggu self.app (lingkup, menerima, mengirim) Kembali Async def send _ wrapper (pesan: ASGISendEvent) - > Tidak ada: #... Lakukan sesuatu Menunggu pengiriman (pesan) Kembali menunggu self.app (lingkup, terima, kirim _ wrapper)
pola umum
Hanya menangani permintaan tertentu
Middleware ASGI dapat menerapkan perilaku tertentu berdasarkan isi scope.
Misalnya, untuk hanya menangani permintaan HTTP, tulis...
Kelas ASGIMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Jika lingkup ["ketik"]! = "http":
Menunggu self.app (lingkup, menerima, mengirim)
Kembali
# Lakukan sesuatu di sini!
Menunggu self.app (lingkup, menerima, mengirim)
Demikian pula, hanya WebSocket middleware yang dilindungi pada scope["type"] != "websocket".
Middleware mungkin juga berperilaku berbeda tergantung pada metode permintaan, URL, header, dan sebagainya.
Komponen Starlette Multiplexing
Starlette menyediakan beberapa struktur data yang menerima parameter ASGI scope,receive, dan / atau send, memungkinkan Anda untuk bekerja pada tingkat abstraksi yang lebih tinggi. Struktur data tersebut termasuk Request,Headers,QueryParams,URL, dan sebagainya.
Misalnya, Anda dapat membuat instansiasi Request untuk memeriksa permintaan HTTP dengan lebih mudah.
Dari bintang. permintaan permintaan impor
Kelas ASGIMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Jika lingkup ["ketik"] = = "http":
Permintaan = Permintaan (ruang lingkup)
... # Gunakan `request.method`,`request.url`,`request.headers`, dll.
Menunggu self.app (lingkup, menerima, mengirim)
Anda juga dapat menggunakan kembali tanggapan, yang juga merupakan aplikasi ASGI.
Kirim tanggapan yang bersemangat
Periksa koneksi scope Memungkinkan Anda untuk memanggil aplikasi ASGI yang berbeda secara bersyarat. Satu kasus penggunaan mungkin untuk mengirim tanggapan tanpa menelepon aplikasi.
Misalnya, middleware ini menggunakan kamus untuk melakukan pengalihan permanen berdasarkan jalur yang diminta. Jika Anda perlu merefactor pola URL perutean, ini dapat digunakan untuk menerapkan dukungan berkelanjutan untuk URL lama.
URL diimpor dari starlette.datastructures
Tanggapan langsung diimpor dari starlette.responses
Pengalihan Kelas Middleware:
Def _ _ init _ _ (diri, aplikasi, path _ mapping: dict):
self.app = aplikasi
Self.path _ mapping = path _ mapping
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Jika lingkup ["ketik"]! = "http":
Menunggu self.app (lingkup, menerima, mengirim)
Kembali
URL = URL (ruang lingkup = ruang lingkup)
Jika url.path dalam diri sendiri. path _ mapping:
Url = url.ganti (path = self.path _ mapping [url.path])
Response = RedirectResponse (url, status _ code = 301)
Menunggu tanggapan (lingkup, menerima, mengirim)
Kembali
Menunggu self.app (lingkup, menerima, mengirim)
Contoh penggunaan akan terlihat seperti ini:
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Rute =...
Pengalihan = {
"/ v1 / sumber daya /": "/ v2 / sumber daya /,"
# ...
}
Peralatan Tengah = [
Middleware (RedirectsMiddleware, path _ mapping=redirections),
]
App = Starlette (rute = rute, middleware=middleware)
Periksa atau Ubah Permintaan
Informasi permintaan dapat diakses atau diubah dengan mengoperasikan scope. Untuk contoh lengkap pola ini, lihat ProxyHeadersMiddleware Uvicorn, yang memeriksa dan menyesuaikan scope saat disajikan di belakang proxy front-end.
Selain itu, membungkus objek yang dapat dipanggil receive ASGI memungkinkan Anda mengakses atau memodifikasi badan permintaan HTTP dengan memanipulasi pesan acara http.request ASGI.
Misalnya, middleware ini menghitung dan mencatat ukuran badan permintaan masuk...
Kelas LoggedRequestBodySizeMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Jika lingkup ["ketik"]! = "http":
Menunggu self.app (lingkup, menerima, mengirim)
Kembali
tubuh _ size = 0
Async def menerima _ logging _ request _ body _ size ():
Ukuran tubuh bukan lokal
Pesan = menunggu menerima ()
Tegaskan pesan ["ketik"] = = "permintaan htp."
tubuh _ size + = len (message.get ("tubuh," b "))
Jika tidak pesan.get ("more _ body," Salah):
Cetak (f "Ukuran badan permintaan adalah: byte{body_size}")
Pesan kembali
Menunggu self.app (scope, receives _ logging _ request _ body _ size, send)
Demikian pula, middleware WebSocket dapat memanipulasi pesan acara websocket.receive ASGI untuk memeriksa atau mengubah data WebSocket yang masuk.
Untuk contoh mengubah isi permintaan HTTP, lihat msgpack-asgi.
Periksa atau ubah tanggapannya
Membungkus send ASGI callable memungkinkan Anda untuk memeriksa atau memodifikasi respon HTTP yang di kirim oleh aplikasi yang mendasarinya. Untuk melakukan ini, bereaksi terhadap pesan peristiwa http.response.start atau http.response.body ASGI.
Misalnya, middleware ini menambahkan beberapa header respons tambahan tetap:
MutableHeader mengimpor dari starlette.datastructures
Kelas ExtraResponseHeadersMiddleware:
Def _ _ init _ _ (diri, aplikasi, header):
self.app = aplikasi
Diri = header
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Jika lingkup ["ketik"]! = "http":
Kembali menunggu self.app (lingkup, menerima, mengirim)
Sinkronisasi def send _ with _ extra _ headers (pesan):
Jika pesan ["ketik"] = = "htp.response.start":
Header = MutableHeader (scope = pesan)
Untuk kunci, nilai dalam self.headers:
Headers.append (kunci, nilai)
Menunggu pengiriman (pesan)
Menunggu self.app (lingkup, menerima, mengirim _ dengan _ extra _ header)
Lihat juga asgi-logger, yang memiliki contoh memeriksa tanggapan HTTP dan mencatat saluran log akses HTTP yang dapat dikonfigurasi.
Demikian pula, WebSocket middleware dapat memanipulasi pesan acara websocket.send ASGI untuk memeriksa atau mengubah data WebSocket yang keluar.
Harap dicatat bahwa jika Anda mengubah tubuh respons, Anda perlu memperbarui header Content-Length respons agar sesuai dengan panjang tubuh respons baru. Lihat brotli-asgi untuk contoh lengkap.
Berikan informasi ke titik akhir
Jika Anda perlu berbagi informasi dengan aplikasi atau titik akhir yang mendasarinya, Anda dapat menyimpannya di kamus scope. Perhatikan bahwa ini adalah konvensi - misalnya, Starlette menggunakan metode ini untuk berbagi informasi perutean dengan titik akhir - tetapi ini bukan bagian dari spesifikasi ASGI.
Jika ya, pastikan untuk menggunakan kunci yang tidak mungkin digunakan oleh middleware atau aplikasi lain untuk menghindari konflik.
Misalnya, titik akhir akan dapat mengakses request.scope["asgi_transaction_id"] ketika middleware berikut disertakan.
Impor uid
Kelas TransactionIDMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Cakupan ["asgi _ transaksi _ id"] = uuid.uuid4 ()
Menunggu self.app (lingkup, menerima, mengirim)
Pembersihan dan penanganan kesalahan
Anda dapat membungkus aplikasi Anda dalam blok try/except/finally atau manajer konteks untuk pembersihan atau penanganan kesalahan.
Misalnya, middleware berikut mungkin mengumpulkan metrik dan menangani pengecualian aplikasi...
Waktu impor
Kelas MonitoringMiddleware:
Def _ _ init _ _ (diri, aplikasi):
self.app = aplikasi
Aync def _ _ call _ _ (diri, lingkup, terima, kirim):
Mulai = waktu ()
Coba:
Menunggu self.app (lingkup, menerima, mengirim)
Kecua*******ecualian sebagai exc:
... # Proses pengecualian
Naikkan
Akhirnya:
Akhir = waktu. Waktu ()
Elapsed = akhir - mulai
... # Kirimkan `elapsed` sebagai metrik ke backend pemantauan
Silakan juga merujuk ke timing-asgi untuk contoh lengkap dari pola ini.
Masalah potensial
Middleware ASGI harus tanpa kewarganegaraan
Karena ASGI dirancang untuk menangani permintaan bersamaan, setiap status khusus koneksi harus dibatasi pada __call__ Dalam lingkup implementasi. Kegagalan untuk melakukannya biasanya menghasilkan tabrakan baca / tulis variabel di seluruh permintaan, dan kesalahan mungkin terjadi.
Misalnya, jika header X-Mock hadir dalam respons, operasi ini secara kondisional menggantikan tubuh respons...
✅ melakukan
```python
from starlette.datastructures import Headers
class MockResponseBodyMiddleware:
def __init__(self, app, content):
self.app = app
self.content = content
async def __call__(self, scope, receive, send):
if scope["type"] != "http":
await self.app(scope, receive, send)
return
# A flag that we will turn `True` if the HTTP response
# has the 'X-Mock' header.
# ✅: Scoped to this function.
should_mock = False
async def maybe_send_with_mock_content(message):
nonlocal should_mock
if message["type"] == "http.response.start":
headers = Headers(raw=message["headers"])
should_mock = headers.get("X-Mock") == "1"
await send(message)
elif message["type"] == "http.response.body":
if should_mock:
message = {"type": "http.response.body", "body": self.content}
await send(message)
await self.app(scope, receive, maybe_send_with_mock_content)
```
❌ Tidak.
```python hl_lines="7-8"
from starlette.datastructures import Headers
class MockResponseBodyMiddleware:
def __init__(self, app, content):
self.app = app
self.content = content
# ❌: This variable would be read and written across requests!
self.should_mock = False
async def __call__(self, scope, receive, send):
if scope["type"] != "http":
await self.app(scope, receive, send)
return
async def maybe_send_with_mock_content(message):
if message["type"] == "http.response.start":
headers = Headers(raw=message["headers"])
self.should_mock = headers.get("X-Mock") == "1"
await send(message)
elif message["type"] == "http.response.body":
if self.should_mock:
message = {"type": "http.response.body", "body": self.content}
await send(message)
await self.app(scope, receive, maybe_send_with_mock_content)
```
Silakan juga merujuk ke GZipMiddleware untuk contoh implementasi lengkap yang membahas masalah potensial ini.
Pembacaan lebih lanjut
Dokumen ini harus cukup sebagai dasar yang baik untuk membuat middleware ASGI.
Namun, ada banyak artikel bagus tentang topik ini:
Menggunakan middleware dalam kerangka kerja lain
Untuk membungkus middleware ASGI di sekitar aplikasi ASGI lainnya, Anda harus menggunakan pola yang lebih umum untuk membungkus instance aplikasi:
Aplikasi = TrustedHostMiddleware (aplikasi, diizinkan _ host = ['example.com'])
Anda juga dapat melakukannya dengan contoh aplikasi Starlette, tetapi lebih baik menggunakan gaya middleware=<List of Middleware instances> karena akan:
- memastikan semuanya terbungkus dalam lapisan terluar
ServerErrorMiddleware. - mempertahankan contoh
apptingkat atas.
Menerapkan middleware ke grup perutean
Middleware juga dapat ditambahkan ke contoh Mount, yang memungkinkan Anda untuk menerapkan middleware ke satu set perutean atau sub-aplikasi.
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.gzip impor GZipMiddleware
Dari bintang. rute impor Gunung, Rute
Rute = [
Gunung (
"/",
Rute = [
Rute (
"/ contoh,"
Endpoint =...,
)
],
Middleware = [Middleware (GZipMiddleware) ]
)
]
Aplikasi = Starlette (rute = rute)
Harap dicatat bahwa middleware yang digunakan dengan cara ini tidak dibungkus dengan pengecualian menangani middleware seperti middleware yang diterapkan pada aplikasi Starlette.
Ini biasanya tidak menjadi masalah karena hanya berfungsi untuk memeriksa atau memodifikasi middleware untuk Response, dan itupun Anda mungkin tidak ingin menerapkan logika ini pada respons kesalahan. Jika Anda ingin menerapkan logika middleware ke respons kesalahan hanya pada rute tertentu, ada beberapa opsi:
- Tambahkan
ExceptionMiddlewarepadaMount - menambahkan blok
try/exceptke middleware Anda dan mengembalikan respons kesalahan dari sana - membagi penandaan dan pemrosesan menjadi dua middleware, satu di tempatkan pada
Mountyang menandai respons yang memerlukan pemrosesan (misalnya dengan mengaturscope["log-response"] = True), dan yang lainnya diterapkan pada aplikasiStarletteuntuk melakukan angkat berat.
Kelas Route/WebSocket juga menerima parameter middleware yang memungkinkan Anda menerapkan middleware ke satu rute:
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.gzip impor GZipMiddleware
Dari starlette. rute impor routing
Rute = [
Rute (
"/ contoh,"
Endpoint =...,
Middleware = [Middleware (GZipMiddleware) ]
)
]
Aplikasi = Starlette (rute = rute)
Anda juga dapat menerapkan middleware ke kelas Router, yang memungkinkan Anda menerapkan middleware ke serangkaian rute:
Starlette.application diimpor dari Starlette
Impor Middleware dari starlette.middleware
Dari starlette.middleware.gzip impor GZipMiddleware
Dari bintang. rute impor Rute, Router
Rute = [
Rute ("/ contoh," titik akhir =...),
Rute ("/ lain," titik akhir =...),
]
Router = Router (rute = rute, middleware = [Middleware (GZipMiddleware) ])
middleware pihak ketiga
Asgi-auth-github
Middleware ini menambahkan otentikasi ke aplikasi ASGI apa pun, yang mengharuskan pengguna untuk masuk dengan akun GitHub mereka (melalui OAuth). Akses dapat dibatasi untuk pengguna tertentu atau anggota organisasi atau tim GitHub tertentu.
agi csrf
Middleware untuk perlindungan terhadap serangan CSRF. Middleware ini mengimplementasikan mode cookie berkomitmen ganda di mana cookie disetel dan kemudian dibandingkan dengan bidang bentuk tersembunyi csrftoken atau header HTTP x-csrftoken.
Peralatan Middleware Otenlib
Alternatif langsung untuk middleware sesi Starlette, menggunakan modul JWT Authlib.
alat tengah Bugsnag
Kelas middleware untuk logging pengecualian untuk Bugsnag.
Peralatan Tengah CSRF
Middleware untuk melindungi dari serangan CSRF. Middleware ini mengimplementasikan mode cookie berkomitmen ganda di mana cookie disetel dan kemudian dibandingkan dengan header HTTP x-csrftoken.
Peralatan tengah data awal
Middleware dan dekorator untuk mendeteksi dan menolak permintaan data TLSv1.3 sebelumnya.
Peralatan tengah prometheus
Kelas middleware untuk menangkap metrik Prometheus terkait dengan permintaan dan tanggapan, termasuk permintaan, waktu, dll...
proxy header middleware
Uvicorn menyertakan kelas middleware untuk menentukan alamat IP sisi klien berdasarkan header X-Forwarded-Proto dan X-Forwarded-For saat menggunakan server proxy. Untuk konfigurasi proxy yang lebih kompleks, Anda mungkin perlu menyesuaikan middleware ini.
nilai pembatas middleware
Middleware yang membatasi tarif. URL pencocokan ekspresi reguler; aturan fleksibel; sangat dapat disesuaikan. Sangat mudah digunakan.
Persyaratan Middleware
Kelas middleware untuk membaca / menghasilkan ID permintaan dan melampirkannya ke log aplikasi.
Peralatan tengah Rollbar
Kelas middleware untuk mencatat pengecualian, kesalahan, dan pesan log ke Rollbar.
StarletteOpentracing
Kelas middleware yang mengirimkan informasi pelacakan ke pelacak yang kompatibel OpenTracing.io dan dapat digunakan untuk menganalisis dan memantau aplikasi terdistribusi.
Peralatan Tengah Kue Keamanan
Middleware yang dapat disesuaikan untuk menambahkan enkripsi dan dekripsi cookie otomatis ke aplikasi Starlette, memberikan dukungan tambahan untuk middleware berbasis cookie yang ada.
pengaturan waktu middleware
Kelas middleware yang memancarkan informasi waktu (waktu CPU dan waktu jam dinding) untuk setiap permintaan yang melewatinya. Termasuk contoh bagaimana memancarkan waktu ini sebagai metrik statistik.
WSGIMiddleware
Kelas middleware yang bertanggung jawab untuk mengonversi aplikasi WSGI ke aplikasi ASGI.