Flutter returns empty string - HTTP(S) GET request

3,528

With any HTTP request, it's a good idea to test the HTTP response code. In your case you are getting 403 Forbidden so your credentials or API key isn't being accepted by the server.

In your first approach you are actually sending two requests to the server - one for each await. Consider changing to:

  http.Response r = await fetchPost();
  print(r.statusCode);
  print(r.body.length);

EDIT - It's your API key that isn't being accepted by the server, which is behaving in a non-standard way.

The Dart HttpClient (which is used directly in the second approach, and indirectly in the first) happens to lower case all request headers. This is perfectly valid because RFC 7230 states "Each header field consists of a case-insensitive field name followed by a colon (":"), optional leading whitespace, the field value, and optional trailing whitespace.".

So, even though you add header "apiKey": "7856d..., what goes out on the wire is apikey: 7856d...

But, (and this is the bit you won't like), it appears that the HTTP server is non-standard and will not accept apikey instead of apiKey. Try changing the Python code to use apikey or APIKEY and you get 403.

(Note that HTTPS makes no difference, you get the same results with HTTP.)

Looks like you need to report this as a bug to Kreta.

Share:
3,528
BoA
Author by

BoA

Updated on December 05, 2022

Comments

  • BoA
    BoA over 1 year

    I have an HTTP(S) GET request which works fine in java (Android sdk) and Python, but when I tried to port it to flutter it returns an empty string. It should return a JSON with ~2MB of data in it.

    Here is the Python code:

    import http.client
    
    HOST, PORT = 'kretaglobalmobileapi.ekreta.hu', 443
    headers = {"apiKey": "7856d350-1fda-45f5-822d-e1a2f3f1acf0", "Connection": "keep-alive",
               "Accept": "application/json", "HOST": "kretaglobalmobileapi.ekreta.hu"}
    
    conn = http.client.HTTPSConnection(host=HOST, port=PORT)
    conn.request("GET", "/api/v1/Institute", headers=headers)
    
    response = conn.getresponse()
    
    data = response.read()
    print(data)
    
    conn.close()
    

    I have tried two different approaches for the Flutter version, none worked.

    First approach:

    import 'dart:async';
    import 'dart:convert' show utf8, json;
    import 'dart:io';
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    
    Future<http.Response> fetchPost() {
      return http.get(
        "https://kretaglobalmobileapi.ekreta.hu/api/v1/Institute",
        // Send authorization headers to your backend
          headers : {"apiKey": "7856d350-1fda-45f5-822d-e1a2f3f1acf0", "Connection": "keep-alive",
            "Accept": "application/json", "HOST": "kretaglobalmobileapi.ekreta.hu"}
      );
    }
    
    void login() async {
    
      print((await fetchPost()).body);
      print((await fetchPost()).body.length);
    
    }
    

    It returns:

    Performing full restart...
    Restarted app in 3,648ms.
    I/flutter (18739): 
    I/flutter (18739): 0
    

    Second:

    Future<Map<String, dynamic>> getInstitutes(HttpClient client) async {
      final String url = "https://kretaglobalmobileapi.ekreta.hu/api/v1/Institute";
    
      final HttpClientRequest request = await client.getUrl(Uri.parse(url))
        ..headers.add("Accept", "application/json")
        ..headers.add("HOST", "kretaglobalmobileapi.ekreta.hu")
        ..headers.add("apiKey", "7856d350-1fda-45f5-822d-e1a2f3f1acf0")
        ..headers.add("Connection", "keep-alive");
    
      final HttpClientResponse response = await request.close();
      print(json.decode(await response.join()));
    
      return json.decode(await response.transform(utf8.decoder).join());
    }
    

    I'm leaving out the GUI and boilerplate code here, the full code is on pastebin.

    Update: The problem was, that the API I was connecting to, used outdated HTTP-standards. I told the support about this, they told me they aren't willing to fix it so I will have to create a new webserver (probably in Python) that will operate between the client and the API. Another option would be to use native Android and iOS code that will hopefully support case-sensitive headers. Huh, all this fuss is because they can't change a capital 'K' to a lowercase 'k'.

    • creativecreatorormaybenot
      creativecreatorormaybenot about 6 years
      Why are you sharing your API key?
    • BoA
      BoA about 6 years
      @creativecreatorormaybenot So it's easier for others to help me and as far as I know it is given to the client before login so I assume it's not tied to an account.
    • Shamshun
      Shamshun over 5 years
      Why did the python code work then? What's different in the flutter version?
    • BoA
      BoA about 5 years
      @Shamshun Sorry, it's a bit late for me to answer, but for future visitors of this question: It worked, because Python still supports case-sensitive headers while flutter doesn't.
  • BoA
    BoA about 6 years
    Thanks, I am getting the 403 Error code, but my API key has to be correct because the same headers are used in the Python code which works perfectly.
  • Günter Zöchbauer
    Günter Zöchbauer about 6 years
    What's the failure reason you get for 403?
  • BoA
    BoA about 6 years
    @GünterZöchbauer I am getting "Forbidden"
  • Günter Zöchbauer
    Günter Zöchbauer about 6 years
    I'd say you have to fix or at least debug that on the server then. We can't know why your server responds with 403.
  • BoA
    BoA about 6 years
    Well Richard Heap was right the server side headers are the problem, they are case-sensitive which is not supported by Flutter (HTTP 1.2 docs states they have to be case-insensitive), I am writing to the guys at Kréta.