5

I want to turn incoming HTTP requests' headers into dictionaries and clone then via the "JSON trick." request.headers is an object that acts like a dictionary, but actually isn't a dictionary.

json.loads(json.dumps(request.headers))

The above-mentioned line of code results in this error:

TypeError: EnvironHeaders([•••]) is not JSON serializable

How do I convert a werkzeug.datastructures.EnvironHeaders object to a dictionary?


Attempt #1:

json.loads(json.dumps({k: v for k, v in request.headers.iteritems()}))

Attempt #2:

json.loads(json.dumps({k: request.headers[k] for k in request.headers.keys()}))

Both of them throw this exception:

ValueError: too many values to unpack

clickbait
  • 2,818
  • 1
  • 25
  • 61

1 Answers1

4

Here is a minimal example that works for sure

headers = werkzeug.datastructures.Headers()
headers.add('Content-Type', 'text/plain')
headers.add('X-Foo', 'bar')
json.dumps({k:v for k, v in headers.iteritems()})

Even if you are using EnvironHeaders,

env = {
    'HTTP_CONTENT_TYPE':        'text/html',
    'CONTENT_TYPE':             'text/html',
    'HTTP_CONTENT_LENGTH':      '0',
    'CONTENT_LENGTH':           '0',
    'HTTP_ACCEPT':              '*',
    'wsgi.version':             (1, 0)
}
headers = werkzeug.datastructures.EnvironHeaders(env)
json.dumps({k:v for k, v in headers.iteritems()})

(Examples copied from test cases in werkzeug.)

Have you inspected request.headers.items() in a debugger?

Like so,

items = request.headers.items()
import ipdb
ipdb.set_trace()   # check type of items; is it an iterable of pairs?
James Lim
  • 12,915
  • 4
  • 40
  • 65
  • 4
    I think this could be clearer. Just use `{k:v for k, v in request.headers.items()}` as the thing to pass to json.dumps(thing). – MrMesees Mar 26 '19 at 10:10
  • @MrMesees hello, i faced the same issue, i got string after json.dump, do you now hot to get dictionary from EnvironHeaders? i tried to convert string to dict but that move breaks request and appears 400 code "Bad Request!" – Артем Черемісін Nov 05 '20 at 10:49
  • Headers can contain multiple values for the same key, and `{k:v for k, v in headers.iteritems()}` will only yield one of those values per key. It would be better to use [`headers.to_wsgi_list()`](https://tedboy.github.io/flask/generated/generated/werkzeug.Headers.to_wsgi_list.html) method instead to produce a list of pairs suitable for json serialization, so as not to lose any data here. – wim Jul 23 '21 at 17:53