Làm cách nào để có được tất cả các tiêu đề yêu cầu trong Django?


107

Tôi cần lấy tất cả các tiêu đề yêu cầu Django. Từ những gì tôi đã đọc, Django chỉ đơn giản là đưa mọi thứ vào request.METAbiến cùng với rất nhiều dữ liệu khác. Cách tốt nhất để lấy tất cả các tiêu đề mà khách hàng đã gửi đến ứng dụng Django của tôi là gì?

Tôi sẽ sử dụng chúng để xây dựng một httplibyêu cầu.

Câu trả lời:


139

Theo tài liệu request.META là một "từ điển Python tiêu chuẩn chứa tất cả các tiêu đề HTTP có sẵn". Nếu bạn muốn có được tất cả các tiêu đề, bạn có thể chỉ cần lặp qua từ điển.

Phần nào trong mã của bạn để thực hiện điều này phụ thuộc vào yêu cầu chính xác của bạn. Bất kỳ nơi nào có quyền truy cập requestnên làm.

Cập nhật

Tôi cần truy cập nó trong một lớp Middleware nhưng khi tôi lặp lại nó, tôi nhận được rất nhiều giá trị ngoài tiêu đề HTTP.

Từ tài liệu:

Ngoại trừ CONTENT_LENGTHCONTENT_TYPE, như đã nêu ở trên, bất kỳ HTTPtiêu đề nào trong yêu cầu đều được chuyển đổi thành METAkhóa bằng cách chuyển đổi tất cả các ký tự thành chữ hoa, thay thế bất kỳ dấu gạch ngang nào bằng dấu gạch dưới và thêm HTTP_tiền tố vào tên .

(Đã nhấn mạnh thêm)

Để chỉ lấy HTTPtiêu đề, chỉ cần lọc theo các khóa có tiền tố HTTP_.

Cập nhật 2

bạn có thể chỉ cho tôi cách tôi có thể xây dựng từ điển tiêu đề bằng cách lọc ra tất cả các khóa từ biến request.META bắt đầu bằng HTTP_ và loại bỏ phần HTTP_ đầu tiên.

Chắc chắn rồi. Đây là một cách để làm điều đó.

import re
regex = re.compile('^HTTP_')
dict((regex.sub('', header), value) for (header, value) 
       in request.META.items() if header.startswith('HTTP_'))

Tôi cần truy cập nó trong một lớp Middleware nhưng khi tôi lặp lại nó, tôi nhận được rất nhiều giá trị ngoài tiêu đề HTTP.
Mridang Agarwalla

Cảm ơn Manoj. Chỉ vì tò mò - bạn có thể chỉ cho tôi cách tôi có thể xây dựng một từ điển tiêu đề bằng cách lọc ra tất cả các khóa từ request.METAbiến bắt đầu bằng một HTTP_và loại bỏ phần đầu HTTP_. Điều này có thể thực hiện thông qua các hàm lambda không? (Tôi nghĩ chúng được gọi là các hàm lambda) Tôi đang hỏi điều này bởi vì tôi có thể sẽ tiếp tục làm điều đó một cách lâu dài bằng cách lần đầu tiên lặp lại chúng, sau đó kiểm tra xem nó có bắt đầu bằng a HTTP_hay không và sau đó thêm nó vào từ điển mới. Cảm ơn một lần nữa.
Mridang Agarwalla

Cảm ơn một lần nữa Manoj. Tôi đã sửa đổi nó một chút để sử dụng lstrip('HTTP_')thay vì regex. :)
Mridang Agarwalla

3
@Mridang Agarwalla: lstripsẽ không thực sự làm những gì bạn yêu cầu nó làm. lstripsẽ loại bỏ tất cả các ký tự đầu phù hợp với bất kỳ ký tự nào trong chuỗi mà bạn cung cấp cho nó, vì vậy nếu bạn có tiêu đề, "HTTP_TOKEN_ID"nó sẽ trả về "OKEN_ID""T"ở đầu các "TOKEN"ký tự khớp với một ký tự trong chuỗi được chuyển đến lstrip. Cách để làm điều đó là prefix = 'HTTP_'; header = header[len(prefix):].
jcdyer

2
Django 2.2 đã hỗ trợ HttpRequest.headers.
Dcalsky

30

Bắt đầu từ Django 2.2, bạn có thể sử dụng request.headersđể truy cập các tiêu đề HTTP. Từ tài liệu trên HttpRequest.headers :

Một đối tượng không phân biệt chữ hoa chữ thường, giống như dict cung cấp quyền truy cập vào tất cả các tiêu đề có tiền tố HTTP (cộng với Nội dung-Độ dài và Loại-Nội dung) từ yêu cầu.

Tên của mỗi tiêu đề được cách điệu bằng cách viết hoa tiêu đề (ví dụ: Tác nhân người dùng) khi nó được hiển thị. Bạn có thể truy cập tiêu đề một cách không phân biệt chữ hoa chữ thường:

>>> 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)

Để nhận tất cả các tiêu đề, bạn có thể sử dụng request.headers.keys()hoặc request.headers.items().


17

Đây là một cách khác để làm điều đó, rất giống với câu trả lời của Manoj Govindan ở trên:

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]

Điều đó cũng sẽ lấy các tiêu đề CONTENT_TYPECONTENT_LENGTHyêu cầu, cùng với các tiêu đề HTTP_. request_headers['some_key]== request.META['some_key'].

Sửa đổi cho phù hợp nếu bạn cần bao gồm / bỏ qua các tiêu đề nhất định. Django liệt kê một loạt, nhưng không phải tất cả, trong số đó ở đây: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

Thuật toán của Django cho các tiêu đề yêu cầu:

  1. Thay dấu gạch ngang -bằng dấu gạch dưới_
  2. Chuyển đổi thành UPPERCASE.
  3. Thêm trước HTTP_vào tất cả các tiêu đề trong yêu cầu ban đầu, ngoại trừ CONTENT_TYPECONTENT_LENGTH.

Giá trị của mỗi tiêu đề không được sửa đổi.


5
Tất cả điều đó có thể được kết hợp thành một regexp duy nhất,re.compile(r'^(HTTP_.+|CONTENT_TYPE|CONTENT_LENGTH)$')
Rebs

6

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

bạn có thể lấy điều đó từ tệp này mặc dù ...


3

Tôi không nghĩ rằng có bất kỳ cách nào dễ dàng để chỉ lấy tiêu đề HTTP. Bạn phải lặp lại request.META dict để có được tất cả những gì bạn cần.

django-debug-toolbar có cùng cách tiếp cận để hiển thị thông tin tiêu đề. Hãy xem tệp này chịu trách nhiệm truy xuất thông tin tiêu đề.


1

Nếu bạn muốn lấy khóa ứng dụng khách từ tiêu đề yêu cầu, bạn có thể thử làm theo các bước sau:

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)

1

Đối với những gì nó đáng giá, có vẻ như mục đích của bạn là sử dụng yêu cầu HTTP đến để tạo thành một yêu cầu HTTP khác. Giống như một cổng vào. Có một mô-đun tuyệt vời django-revproxy hoàn thành chính xác điều này.

Nguồn là một tài liệu tham khảo khá tốt về cách hoàn thành những gì bạn đang cố gắng làm.


0
<b>request.META</b><br>
{% for k_meta, v_meta in request.META.items %}
  <code>{{ k_meta }}</code> : {{ v_meta }} <br>
{% endfor %}

0

Đơn giản, bạn có thể sử dụng HttpRequest.headers từ Django 2.2 trở đi. Ví dụ sau được lấy trực tiếp từ Tài liệu Django chính thức trong phần Đối tượng yêu cầu và phản hồi .

>>> 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.