ฉันจะรับส่วนหัวคำขอทั้งหมดใน Django ได้อย่างไร


107

ฉันต้องการรับส่วนหัวคำขอ Django ทั้งหมด จากสิ่งที่ฉันอ่าน Django เพียงแค่ทิ้งทุกอย่างลงในrequest.METAตัวแปรพร้อมกับข้อมูลอื่น ๆ อีกมากมาย วิธีใดเป็นวิธีที่ดีที่สุดในการรับส่วนหัวทั้งหมดที่ลูกค้าส่งไปยังแอปพลิเคชัน Django ของฉัน

ฉันจะใช้สิ่งเหล่านี้เพื่อสร้างhttplibคำขอ

คำตอบ:


139

ตามเอกสารประกอบ request.METAคือ "พจนานุกรม Python มาตรฐานที่มีส่วนหัว HTTP ที่มีทั้งหมด" หากคุณต้องการรับส่วนหัวทั้งหมดคุณสามารถทำซ้ำได้จากพจนานุกรม

ส่วนใดของโค้ดของคุณในการทำสิ่งนี้ขึ้นอยู่กับความต้องการของคุณ ทุกที่ที่สามารถเข้าถึงได้requestควรทำ

อัปเดต

ฉันต้องการเข้าถึงมันในคลาสมิดเดิลแวร์ แต่เมื่อฉันทำซ้ำฉันจะได้รับค่ามากมายนอกเหนือจากส่วนหัว HTTP

จากเอกสารประกอบ:

มีข้อยกเว้นของCONTENT_LENGTHและCONTENT_TYPEเป็นดังกล่าวข้างต้นใด ๆHTTPส่วนหัวในคำขอจะถูกแปลงเป็นMETAคีย์โดยการแปลงตัวอักษรทั้งหมดเป็นตัวพิมพ์ใหญ่แทนยัติภังค์ใด ๆ กับขีดและเพิ่มHTTP_คำนำหน้าชื่อ

(เน้นเพิ่ม)

หากต้องการรับHTTPส่วนหัวเพียงอย่างเดียวให้กรองตามคีย์ที่HTTP_ขึ้นต้นด้วย

อัปเดต 2

คุณช่วยแสดงให้ฉันเห็นได้ไหมว่าฉันจะสร้างพจนานุกรมของส่วนหัวได้อย่างไรโดยการกรองคีย์ทั้งหมดออกจากคำขอตัวแปร META ซึ่งขึ้นต้นด้วย HTTP_ และดึงส่วน HTTP_ ชั้นนำออก

แน่นอน นี่คือวิธีหนึ่งที่จะทำได้

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

ฉันต้องการเข้าถึงมันในคลาสมิดเดิลแวร์ แต่เมื่อฉันทำซ้ำฉันจะได้รับค่ามากมายนอกเหนือจากส่วนหัว HTTP
Mridang Agarwalla

ขอบคุณ Manoj เพียงแค่อยากรู้ - คุณช่วยแสดงให้ฉันเห็นได้ไหมว่าฉันจะสร้างพจนานุกรมของส่วนหัวได้อย่างไรโดยการกรองคีย์ทั้งหมดออกจากrequest.METAตัวแปรซึ่งเริ่มต้นด้วย a HTTP_และดึงHTTP_ส่วนที่นำหน้าออก เป็นไปได้ผ่านฟังก์ชั่นแลมบ์ดาหรือไม่? (ฉันคิดว่าพวกเขาเรียกว่าฟังก์ชันแลมบ์ดา) ฉันถามสิ่งนี้เพราะฉันอาจจะทำต่อไปเรื่อย ๆ โดยการวนซ้ำก่อนจากนั้นตรวจสอบดูว่ามันขึ้นต้นด้วย a HTTP_แล้วเพิ่มลงในพจนานุกรมใหม่หรือไม่ ขอบคุณอีกครั้ง.
Mridang Agarwalla

ขอบคุณ Manoj อีกครั้ง ฉันแก้ไขเล็กน้อยเพื่อใช้lstrip('HTTP_')แทนนิพจน์ทั่วไป :)
Mridang Agarwalla

3
@Mridang Agarwalla: lstripจะไม่ทำในสิ่งที่คุณขอให้ทำจริงๆ lstripจะตัดอักขระนำหน้าทั้งหมดที่ตรงกับอักขระใด ๆ ในสตริงที่คุณให้ไว้ดังนั้นหากคุณมีส่วนหัว"HTTP_TOKEN_ID"ก็จะให้กลับ"OKEN_ID"เนื่องจากใน"T"ตอนต้นของการ"TOKEN"จับคู่อักขระในสตริงที่ส่งไปยัง lstrip prefix = 'HTTP_'; header = header[len(prefix):]วิธีที่จะทำคือ
jcdyer

2
รองรับ Django 2.2 HttpRequest.headersแล้ว
Dcalsky

30

เริ่มจาก Django 2.2 คุณสามารถใช้request.headersเพื่อเข้าถึงส่วนหัว HTTP จากเอกสารเกี่ยวกับ HttpRequest.headers :

อ็อบเจ็กต์ที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่เหมือน dict ที่ให้การเข้าถึงส่วนหัว HTTP ที่นำหน้าทั้งหมด (รวมทั้ง Content-Length และ Content-Type) จากคำขอ

ชื่อของแต่ละส่วนหัวจะมีสไตล์ด้วยปลอกหัวเรื่อง (เช่น User-Agent) เมื่อแสดงขึ้น คุณสามารถเข้าถึงส่วนหัวโดยไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่:

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

ที่จะได้รับส่วนหัวทั้งหมดคุณสามารถใช้หรือrequest.headers.keys()request.headers.items()


17

นี่เป็นอีกวิธีหนึ่งที่ทำได้คล้ายกับคำตอบของManoj Govindanข้างต้น:

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]

ที่ยังจะคว้าCONTENT_TYPEและCONTENT_LENGTHคำขอส่วนหัวพร้อมกับHTTP_คน request_headers['some_key]== request.META['some_key'].

แก้ไขตามหากคุณต้องการรวม / ละเว้นส่วนหัวบางส่วน Django แสดงรายการจำนวนมาก แต่ไม่ใช่ทั้งหมดที่นี่: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META

อัลกอริทึมของ Django สำหรับส่วนหัวของคำขอ:

  1. แทนที่ยัติภังค์-ด้วยขีดล่าง_
  2. แปลงเป็น UPPERCASE
  3. ย่อหน้าHTTP_ไปส่วนหัวทั้งหมดในคำขอเดิมยกเว้นและCONTENT_TYPECONTENT_LENGTH

ค่าของแต่ละส่วนหัวควรไม่มีการแก้ไข


5
ทั้งหมดนี้สามารถรวมกันเป็น regexp เดียวre.compile(r'^(HTTP_.+|CONTENT_TYPE|CONTENT_LENGTH)$')
Rebs


3

ฉันไม่คิดว่าจะมีวิธีง่ายๆในการรับเฉพาะส่วนหัว HTTP คุณต้องทำซ้ำตามคำขอ META dict เพื่อให้ได้สิ่งที่คุณต้องการทั้งหมด

django-debug-toolbar ใช้แนวทางเดียวกันในการแสดงข้อมูลส่วนหัว ดูไฟล์นี้ที่รับผิดชอบในการดึงข้อมูลส่วนหัว


1

หากคุณต้องการรับรหัสไคลเอ็นต์จากส่วนหัวของคำขอคุณสามารถลองทำตาม:

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

สิ่งที่คุ้มค่าดูเหมือนว่าเจตนาของคุณคือใช้คำขอ HTTP ขาเข้าเพื่อสร้างคำขอ HTTP อื่น จัดเรียงเหมือนเกตเวย์ มีโมดูลdjango-revproxyที่ยอดเยี่ยมที่ทำได้ตามนี้

แหล่งที่มานี้เป็นข้อมูลอ้างอิงที่ดีในการทำสิ่งที่คุณพยายามทำ



0

เพียงแค่คุณสามารถใช้HttpRequest.headersตั้งแต่Django 2.2เป็นต้นไป ตัวอย่างต่อไปนี้จะถูกนำมาโดยตรงจากทางการเอกสาร Djangoภายใต้การขอและการตอบสนองวัตถุส่วน

>>> 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.