【问题标题】:Django cookies and headersDjango cookie 和标头
【发布时间】:2013-02-13 23:32:59
【问题描述】:


在 Django 中(和一般情况下),cookie 也是一个标题,就像,例如User-Agent?
也就是说,这两种方法在 Django 中是否等效?

使用set_cookie:

response.set_cookie('food', 'bread')
response.set_cookie('drink', 'water')

使用标题设置:

response['Cookie'] = ('food=bread; drink=water')
# I'm not sure whether 'Cookie' should be capitalized or not


另外,如果我们可以使用第二种方式设置 cookie,我们如何包含附加信息,
比如字符串中的pathmax_age等?我们可以用一些特殊的方法将它们分开
人物?

【问题讨论】:

    标签: python django cookies


    【解决方案1】:

    如果您使用set_cookie 会容易得多。但是,是的,您可以通过以下方式设置 cookie 设置响应头:

    response['Set-Cookie'] = ('food=bread; drink=water; Path=/; max_age=10')
    

    但是,由于在 response 对象中重置 Set-Cookie 会清除之前的 一,你在 Django 中不能有多个 Set-Cookie 标头。让我们来看看 为什么。

    response.py, set_cookie method观察:

    class HttpResponseBase:
    
        def __init__(self, content_type=None, status=None, mimetype=None):
            # _headers is a mapping of the lower-case name to the original case of
            # the header (required for working with legacy systems) and the header
            # value. Both the name of the header and its value are ASCII strings.
            self._headers = {}
            self._charset = settings.DEFAULT_CHARSET
            self._closable_objects = []
            # This parameter is set by the handler. It's necessary to preserve the
            # historical behavior of request_finished.
            self._handler_class = None
            if mimetype:
                warnings.warn("Using mimetype keyword argument is deprecated, use"
                              " content_type instead",
                              DeprecationWarning, stacklevel=2)
                content_type = mimetype
            if not content_type:
                content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
                        self._charset)
            self.cookies = SimpleCookie()
            if status:
                self.status_code = status
    
            self['Content-Type'] = content_type
    
        ...
    
        def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                       domain=None, secure=False, httponly=False):
            """
            Sets a cookie.
    
            ``expires`` can be:
            - a string in the correct format,
            - a naive ``datetime.datetime`` object in UTC,
            - an aware ``datetime.datetime`` object in any time zone.
            If it is a ``datetime.datetime`` object then ``max_age`` will be calculated.
    
            """
            self.cookies[key] = value
            if expires is not None:
                if isinstance(expires, datetime.datetime):
                    if timezone.is_aware(expires):
                        expires = timezone.make_naive(expires, timezone.utc)
                    delta = expires - expires.utcnow()
                    # Add one second so the date matches exactly (a fraction of
                    # time gets lost between converting to a timedelta and
                    # then the date string).
                    delta = delta + datetime.timedelta(seconds=1)
                    # Just set max_age - the max_age logic will set expires.
                    expires = None
                    max_age = max(0, delta.days * 86400 + delta.seconds)
                else:
                    self.cookies[key]['expires'] = expires
            if max_age is not None:
                self.cookies[key]['max-age'] = max_age
                # IE requires expires, so set it if hasn't been already.
                if not expires:
                    self.cookies[key]['expires'] = cookie_date(time.time() +
                                                               max_age)
            if path is not None:
                self.cookies[key]['path'] = path
            if domain is not None:
                self.cookies[key]['domain'] = domain
            if secure:
                self.cookies[key]['secure'] = True
            if httponly:
                self.cookies[key]['httponly'] = True
    

    这里有两点值得注意:

    1. set_cookie 方法将负责处理 datetime 中的 expires 为您,如果您自己设置,则必须自己设置。
    2. self.cookie 是一本词典。因此,每个key 都会在标题中添加一个["Set-Cookie"],您很快就会看到。

    HttpResponse 中的 cookies 对象将被传递给 WSGIHandler,并附加到响应头中:

    response_headers = [(str(k), str(v)) for k, v in response.items()]
    for c in response.cookies.values():
        response_headers.append((str('Set-Cookie'), str(c.output(header=''))))
    

    上面的代码也是为什么只有set_cookie()允许在响应头中有多个Set-Cookie,而将cookie直接设置为Response对象只会返回一个Set-Cookie

    【讨论】:

      【解决方案2】:

      当然,但是将“Cookie”更改为“Set-Cookie”并添加“Path=/”以使其在站点范围内。

      response["Set-Cookie"] = "food=bread; drink=water; Path=/"
      

      编辑:

      在我自己尝试之后,我发现了一个有趣的怪癖,set_cookie 不会将相似的 cookie(相同的路径、过期、域等)组合在同一个标​​头中。它只是在响应中添加了另一个“Set-Cookie”。可以理解,因为检查和弄乱字符串可能比在 HTTP 标头中添加一些额外的字节要花费更多的时间(并且充其量只是一个微优化)。

      response.set_cookie("food",  "kabanosy")
      response.set_cookie("drink", "ardbeg")
      response.set_cookie("state", "awesome")
      
      # result in these headers
      #   Set-Cookie: food=kabonosy; Path=/
      #   Set-Cookie: drink=ardbeg; Path=/
      #   Set-Cookie: state=awesome; Path=/
      
      # not this
      #   Set-Cookie:food=kabanosy; drink=ardbeg; state=awesome; Path=/
      

      【讨论】:

      • 那么,如果我要设置两个不同的 cookie,使用不同的 pathmax_age 参数呢?但使用response["Set-Cookie"]=... 语法?
      • 老实说,您最好使用set_cookie,因为自己设置标题并没有真正的好处。不过会是这样的:response["Set-Cookie"] = "food=kabanosy; Max-Age=86400; Path=/".
      • 我知道使用set_cookie基本上更方便,但我想了解它与HttpResponse对象和标题的关系。
      • 无论如何,我在帖子上写了一个答案,对您探索的行为进行了一些解释,关于set_cookie在响应中设置多个Set-Cookies。
      【解决方案3】:

      来自HttpResponse类代码的sn-p:

      class HttpResponse(object):
      
          #...
      
          def __init__(self, content='', mimetype=None, status=None,
      
              #...
      
              self.cookies = SimpleCookie()
      
          #...
      
          def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                         domain=None, secure=False, httponly=False):
      
              self.cookies[key] = value
      
              #...
      


      也就是说,每当调用 response.set_cookie() 时,它要么在 response.cookies[key] 处放置一个新的 cookie
      value,要么更改现有值(如果该键上有一个值)。
      它解释了为什么它设置多个 Set-Cookie 标头。
      我想知道我们如何使用response['Set-Cookie'] 做同样的事情。

      【讨论】:

        猜你喜欢
        • 2016-11-26
        • 1970-01-01
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 1970-01-01
        • 2019-03-26
        • 2018-07-29
        • 2021-01-08
        相关资源
        最近更新 更多