async 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, headers, body)
        self.logger.debug("%s %s, Request: %s %s", method, url, headers, body)

        encoded_body = body.encode() if body else None
        session_method = getattr(self.session, method.lower())

        response = None
        http_response = None
        json_response = None
        try:
            async with session_method(yarl.URL(url, encoded=True),
                                      data=encoded_body,
                                      headers=request_headers,
                                      timeout=(self.timeout / 1000),
                                      proxy=self.aiohttp_proxy) as response:
                http_response = await response.text()
                json_response = self.parse_json(http_response) if self.is_json_encoded_object(http_response) else None
                headers = response.headers
                if self.enableLastHttpResponse:
                    self.last_http_response = http_response
                if self.enableLastResponseHeaders:
                    self.last_response_headers = headers
                if self.enableLastJsonResponse:
                    self.last_json_response = json_response
                if self.verbose:
                    print("\nResponse:", method, url, response.status, headers, http_response)
                self.logger.debug("%s %s, Response: %s %s %s", method, url, response.status, headers, http_response)

        except socket.gaierror as e:
            self.raise_error(ExchangeNotAvailable, url, method, e, None)

        except concurrent.futures._base.TimeoutError as e:
            self.raise_error(RequestTimeout, method, url, e, None)

        except aiohttp.client_exceptions.ClientConnectionError as e:
            self.raise_error(ExchangeNotAvailable, url, method, e, None)

        except aiohttp.client_exceptions.ClientError as e:  # base exception class
            self.raise_error(ExchangeError, url, method, e, None)

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