def fetch(self, url, method='GET', headers=None, body=None):
        """Perform a HTTP request and return decoded JSON data"""
        request_headers = self.prepare_request_headers(headers)
        url = self.proxy + url

        if self.verbose:
            print("\nRequest:", method, url, request_headers, body)
        self.logger.debug("%s %s, Request: %s %s", method, url, request_headers, body)

        if body:
            body = body.encode()

        self.session.cookies.clear()

        response = None
        http_response = None
        json_response = None
        try:
            response = self.session.request(
                method,
                url,
                data=body,
                headers=request_headers,
                timeout=int(self.timeout / 1000),
                proxies=self.proxies
            )
            http_response = response.text
            json_response = self.parse_json(http_response) if self.is_json_encoded_object(http_response) else None
            headers = response.headers
            # FIXME remove last_x_responses from subclasses
            if self.enableLastHttpResponse:
                self.last_http_response = http_response
            if self.enableLastJsonResponse:
                self.last_json_response = json_response
            if self.enableLastResponseHeaders:
                self.last_response_headers = headers
            if self.verbose:
                print("\nResponse:", method, url, response.status_code, headers, http_response)
            self.logger.debug("%s %s, Response: %s %s %s", method, url, response.status_code, headers, http_response)
            response.raise_for_status()

        except Timeout as e:
            self.raise_error(RequestTimeout, method, url, e)

        except TooManyRedirects as e:
            self.raise_error(ExchangeError, url, method, e)

        except SSLError as e:
            self.raise_error(ExchangeError, url, method, e)

        except HTTPError as e:
            self.handle_errors(response.status_code, response.reason, url, method, headers, http_response, json_response)
            self.handle_rest_errors(e, response.status_code, http_response, url, method)
            self.raise_error(ExchangeError, url, method, e, http_response)

        except RequestException as e:  # base exception class
            error_string = str(e)
            if ('ECONNRESET' in error_string) or ('Connection aborted.' in error_string):
                self.raise_error(NetworkError, url, method, e)
            else:
                self.raise_error(ExchangeError, url, method, e)

        self.handle_errors(response.status_code, response.reason, url, method, headers, http_response, json_response)
        self.handle_rest_response(http_response, json_response, url, method, headers, body)
        if json_response is not None:
            return json_response
        return http_response