Jak mogę uzyskać wszystkie nagłówki żądań w Django?

107

Muszę pobrać wszystkie nagłówki żądań Django. Z tego, co przeczytałem, Django po prostu zrzuca wszystko do request.METAzmiennej wraz z wieloma innymi danymi. Jaki byłby najlepszy sposób na pobranie wszystkich nagłówków, które klient wysłał do mojej aplikacji Django?

Użyję ich do zbudowania httplibżądania.

Mridang Agarwalla
źródło

Odpowiedzi:

139

Zgodnie z dokumentacją request.META jest to „standardowy słownik Pythona zawierający wszystkie dostępne nagłówki HTTP”. Jeśli chcesz uzyskać wszystkie nagłówki, możesz po prostu przejść przez słownik.

To, która część kodu ma to zrobić, zależy od dokładnych wymagań. Każde miejsce, do którego ma dostęp, requestpowinno wystarczyć.

Aktualizacja

Muszę uzyskać do niego dostęp w klasie Middleware, ale kiedy iteruję nad nim, otrzymuję wiele wartości oprócz nagłówków HTTP.

Z dokumentacji:

Z wyjątkiem CONTENT_LENGTHi CONTENT_TYPE, jak podano powyżej, wszystkie HTTPnagłówki w żądaniu są konwertowane na METAklucze, konwertując wszystkie znaki na wielkie litery, zastępując wszelkie łączniki podkreśleniami i dodając HTTP_przedrostek do nazwy .

(Podkreślenie dodane)

Aby uzyskać HTTPsame nagłówki, po prostu przefiltruj według kluczy z prefiksem HTTP_.

Zaktualizuj 2

czy możesz mi pokazać, jak mogę zbudować słownik nagłówków, odfiltrowując wszystkie klucze ze zmiennej request.META, które zaczynają się od HTTP_ i usuwają wiodącą część HTTP_.

Pewnie. Oto jeden sposób, aby to zrobić.

import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value) 
       in request.META.items() if header.startswith('HTTP_'))
Manoj Govindan
źródło
Muszę uzyskać do niego dostęp w klasie Middleware, ale kiedy iteruję nad nim, otrzymuję wiele wartości oprócz nagłówków HTTP.
Mridang Agarwalla
Dzięki Manoj. Tak z ciekawości - czy mógłbyś mi pokazać, jak mogę zbudować słownik nagłówków, odfiltrowując wszystkie klucze ze request.METAzmiennej, która zaczyna się od a HTTP_i usuwając wiodącą HTTP_część. Czy jest to możliwe dzięki funkcjom lambda? (Myślę, że nazywają się funkcjami lambda) Pytam o to, ponieważ prawdopodobnie zrobiłbym to długo, najpierw iterując po nich, a następnie sprawdzając, czy zaczyna się od a, HTTP_a następnie dodając go do nowego słownika. Dzięki jeszcze raz.
Mridang Agarwalla
Jeszcze raz dziękuję Manoj. Zmodyfikowałem go nieznacznie, aby użyć lstrip('HTTP_')zamiast wyrażenia regularnego. :)
Mridang Agarwalla
3
@Mridang Agarwalla: lstriptak naprawdę nie zrobi tego, o co go prosisz. lstripusunie wszystkie początkowe znaki, które pasują do dowolnych znaków w ciągu, który mu podasz, więc jeśli masz nagłówek "HTTP_TOKEN_ID", zwróci "OKEN_ID", ponieważ "T"na początku "TOKEN"dopasowania znak w ciągu przekazany do lstrip. Sposób na to jest prefix = 'HTTP_'; header = header[len(prefix):].
jcdyer
2
Obsługiwane jest Django 2.2 HttpRequest.headers.
Dcalsky
30

Począwszy od Django 2.2, możesz użyć, request.headersaby uzyskać dostęp do nagłówków HTTP. Z dokumentacji na HttpRequest.headers :

Obiekt podobny do dyktowania bez rozróżniania wielkości liter, który zapewnia dostęp do wszystkich nagłówków z prefiksem HTTP (plus Content-Length i Content-Type) z żądania.

Nazwa każdego nagłówka jest stylizowana na wielkość liter (np. User-Agent), gdy jest wyświetlana. Możesz uzyskać dostęp do nagłówków bez rozróżniania wielkości liter:

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

Aby uzyskać wszystkie nagłówki, możesz użyć request.headers.keys()lub request.headers.items().

Daniel Hepper
źródło
17

Jest to inny sposób na zrobienie tego, bardzo podobny do powyższej odpowiedzi Manoj Govindana :

import re
regex_http_          = re.compile(r'^HTTP_.+$')
regex_content_type   = re.compile(r'^CONTENT_TYPE$')
regex_content_length = re.compile(r'^CONTENT_LENGTH$')

request_headers = {}
for header in request.META:
    if regex_http_.match(header) or regex_content_type.match(header) or regex_content_length.match(header):
        request_headers[header] = request.META[header]

Spowoduje to również pobranie nagłówków CONTENT_TYPEi CONTENT_LENGTHżądań wraz z innymi HTTP_. request_headers['some_key]== request.META['some_key'].

Zmodyfikuj odpowiednio, jeśli chcesz dołączyć / pominąć niektóre nagłówki. Django wymienia kilka z nich, ale nie wszystkie, tutaj: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Algorytm Django dla nagłówków żądań:

  1. Zastąp myślnik -podkreśleniem_
  2. Konwertuj na WIELKIE LITERY.
  3. Dołącz HTTP_do wszystkich nagłówków w pierwotnym żądaniu, z wyjątkiem CONTENT_TYPEi CONTENT_LENGTH.

Wartości każdego nagłówka nie powinny być modyfikowane.

Dave
źródło
5
To wszystko można połączyć w jedno wyrażenie regularne,re.compile(r'^(HTTP_.+|CONTENT_TYPE|CONTENT_LENGTH)$')
Rebs
6

request.META.get („HTTP_AUTHORIZATION”) /python3.6/site-packages/rest_framework/authentication.py

możesz to jednak uzyskać z tego pliku ...

James Vare Samuel
źródło
3

Nie sądzę, aby istniał łatwy sposób na uzyskanie tylko nagłówków HTTP. Musisz iterować poprzez request.META dyktuje, aby uzyskać wszystko, czego potrzebujesz.

django-debug-toolbar stosuje to samo podejście do wyświetlania informacji w nagłówku. Spójrz na ten plik odpowiedzialny za pobieranie informacji z nagłówka.

Srikanth Chundi
źródło
1

Jeśli chcesz uzyskać klucz klienta z nagłówka żądania, możesz spróbować wykonać następujące czynności:

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from apps.authentication.models import CerebroAuth

class CerebroAuthentication(BaseAuthentication):
def authenticate(self, request):
    client_id = request.META.get('HTTP_AUTHORIZATION')
    if not client_id:
        raise exceptions.AuthenticationFailed('Client key not provided')
    client_id = client_id.split()
    if len(client_id) == 1 or len(client_id) > 2:
        msg = ('Invalid secrer key header. No credentials provided.')
        raise exceptions.AuthenticationFailed(msg)
    try:
        client = CerebroAuth.objects.get(client_id=client_id[1])
    except CerebroAuth.DoesNotExist:
        raise exceptions.AuthenticationFailed('No such client')
    return (client, None)
Tony Aziz
źródło
1

Wydaje się, że Twoim zamiarem jest użycie przychodzącego żądania HTTP do utworzenia kolejnego żądania HTTP. Coś jak brama. Istnieje doskonały moduł django-revproxy, który dokładnie to robi .

Źródło jest całkiem dobrym źródłem informacji o tym, jak osiągnąć to, co próbujesz zrobić.

abhayAndPoorvisDad
źródło
0
<b>request.META</b><br>
{% for k_meta, v_meta in request.META.items %}
  <code>{{ k_meta }}</code> : {{ v_meta }} <br>
{% endfor %}
S. Nick
źródło
0

Po prostu możesz użyć HttpRequest.headers od Django 2.2 i nowszych . Poniższy przykład pochodzi bezpośrednio z oficjalnej dokumentacji Django w sekcji Obiekty zapytań i odpowiedzi .

>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}

>>> 'User-Agent' in request.headers
True
>>> 'user-agent' in request.headers
True

>>> request.headers['User-Agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers['user-agent']
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)

>>> request.headers.get('User-Agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
>>> request.headers.get('user-agent')
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
Kushan Gunasekera
źródło