Allow passing a JSONEncoder and JSONDecoder

The python json module supports a custom [JSONEncoder] and [JSONDecoder]. This enables to serialize / deserialize custom data formats. Since requests just passes JSON data directly to `json.dumps` and `json.loads`, it is not possible to customize JSON serialization at all. As a result one must configure configure the JSON request manually, meaning the content type needs to be set manually.

I suggest to add the ability to pass custom `json_encoder` and `json_decoder` properties to requests. This handles pretty much all other arguments that could be passed to `json.dumps` and `json.loads` as well.

This example:

```python
response = requests.post(
    'https://www.example.com',
    content_type='application/json',
    data=json.dumps(data, cls=MyEncoder))
result = json.loads(response.text, cls=MyDecoder)
```

would become:

```python
response = requests.post(
    'https://www.example.com',
    json=data,
    json_encoder=MyEncoder,
    json_decoder=MyDecoder)
result = response.json()
```

I could even imagine that it's useful to pass these arguments to the session constructor, because data from one session might often contain the same types of data serialization.

```python
session = requests.Session(json_encoder=MyEncoder, json_decoder=MyDecoder)

response = session.post('https://www.example.com', json=data)
result = response.json()
```


[JSONDecoder]: https://docs.python.org/3.6/library/json.html#json.JSONDecoder
[JSONEncoder]: https://docs.python.org/3.6/library/json.html#json.JSONEncoder


Thanks for this suggestion!

It's been provided before and was rejected (see #2755): the same argument applies here, I'm afraid. This is just too minor in utility to justify adding the extra kwargs: `json=` triggers only a tiny amount of code that can easily be replicated in your own application. :smile:

Agreed!

@Lukasa @kennethreitz  I have to disagree. It is probably simple workaround for **request** JSON. But what about **response** JSON? `requests`  uses built-in decoder and if you want later inspect and transform that JSON response - it will require recursively analyze and convert them (in case of complex nested json objects) - what is definitely not what we want . 
Consider following scenario:

1. `POST` JSON object to server, which contains strings with zoned datetime
2. Database does know nothing about timezone of user and convert to internal representation (`UTC`)
3. `GET`  JSON object from server, zoned datetime will be the same, but with different string representation
4. Compare that two JSON objects are identical
Step 4 will require some kind of normalization of JSONs - for example convert strings to datetime or  [Arrow](http://arrow.readthedocs.io/en/latest/) object and compare that objects.
If `requests` doesn't provide custom decoders - user have recursively (and safe, without stack overflow) walk over JSON tree structure (same job done twice).
 _I think it greatly complicates things._

@likern Not really. Just use `response.content` instead of `response.json()` and pass to your own custom decoder instead. One extra line of code. Doesn't seem to be a great increase in complexity to me. :wink: