dart-lang / http

A composable API for making HTTP requests in Dart.
https://pub.dev/packages/http
BSD 3-Clause "New" or "Revised" License
1.01k stars 351 forks source link

Invalid header field name, with 128 #416

Closed valehasadli closed 4 years ago

valehasadli commented 4 years ago

Hi guys, I got a problem with the header.

Invalid header field name, with 128

I'm using an iOS simulator. And if I not mistaken iOS simulator works well with localhost, in general, I have an information emulator that cannot access the localhost. That's why I have a decision it is maybe a bug.

When I use another header such as

headers: {
   HttpHeaders.contentTypeHeader: 'application/json'
},

After that, I got different errors like that.

flutter: Bad state: Cannot set the body fields of a Request with content-type "application/json".

One important thing FYI, when I use the JSON MOCK SERVER, it works very well, after switching DOCKER environment I got the error. I would like to add other details. I also test my real back-end code which is works on the docker environment, I test on the browser with fetch API, and also angular application works well. I think that there is not related to my back-end or such kind of CORS issues.

   Future<void> login(String email, String password) async {
    final String url = '$baseUrl/login';

    try {
      final http.Response response = await http.post(
        url,
        headers: <String, String>{
          HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
        },
        body: jsonEncode(<String, String>{
          'email': email,
          'password': password,
          'device_name': 'apple',
        }),
      );

      final Login user = Login.fromJson(json.decode(response.body));

      _token = user.data.token;
      _email = email;

      final SharedPreferences sharedPreferences =
          await SharedPreferences.getInstance();
      final userData = json.encode({
        'token': _token,
        'email': _email,
      });
      sharedPreferences.setString('userData', userData);

      notifyListeners();
    } on HttpException {
      print('login service error.');
    } on SocketException {
      print('No internet connection or server shutdown.');
    } on FormatException {
      print('Bad response format.');
    } catch (exception) {
      throw exception;
    }
  }
suztomo commented 4 years ago

What’s the stacktrace of the error?

valehasadli commented 4 years ago

What’s the stacktrace of the error?

I got only this error from my console.

valehasadli commented 4 years ago

What’s the stacktrace of the error?

https://flutter.dev/docs/cookbook/networking/send-data I don't see a difference between the examples in the book

suztomo commented 4 years ago

Do you know until which line your code is working?

valehasadli commented 4 years ago

Do you know until which line your code is working?

it works until try.

suztomo commented 4 years ago

What happens if you simplify the function to focus on the error?

  Future<void> login(String email, String password) async {
   final String url = '$baseUrl/login';
   final jsonBody = jsonEncode(<String, String>{
         'email': email,
         'password': password,
         'device_name': 'apple',
       });
   final http.Response response = await http.post(
       url,
       headers: <String, String>{
         HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
       },
       body: jsonBody,
     );

    // An error happens before this print statement
    print("Got response: $response");
  }

Does this show more information such as stacktrace?

valehasadli commented 4 years ago

What happens if you simplify the function to focus on the error?

  Future<void> login(String email, String password) async {
   final String url = '$baseUrl/login';
   final jsonBody = jsonEncode(<String, String>{
         'email': email,
         'password': password,
         'device_name': 'apple',
       });
   final http.Response response = await http.post(
       url,
       headers: <String, String>{
         HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
       },
       body: jsonBody,
     );

    // An error happens before this print statement
    print("Got response: $response");
  }

Does this show more information such as stacktrace?

I've tried also, but the same error, exception handler catches the problem before I think and that's why this way did not help me detect the problem.

suztomo commented 4 years ago

Do you observe "Got response: $response" printed? It's either

valehasadli commented 4 years ago

Do you observe "Got response: $response" printed? It's either

  • It prints some value at "Got response: $response", or
  • http.post throws an exception and your code (caller of login) suppresses the exception.

Here is the stacktrace

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: Invalid header field name, with 128
#0      AuthProvider.login (package:translationsolvermobile/providers/auth_provider.dart:88:7)
<asynchronous suspension>
#1      _LoginScreenState._submitForm (package:translationsolvermobile/screens/login_screen.dart:44:7)
#2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
#3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
#5      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:504:11)
#6      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:282:5)
#7      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:217:7)
#8      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
#9      PointerRouter._dispatch<…>
valehasadli commented 4 years ago

@suztomo stacktrace

flutter: http://localhost:8000/api/mobile/auth/login
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: Invalid header field name, with 128
#0      AuthProvider.login (package:translationsolvermobile/providers/auth_provider.dart:88:7)
<asynchronous suspension>
#1      _LoginScreenState._submitForm (package:translationsolvermobile/screens/login_screen.dart:44:7)
#2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
#3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
#5      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:504:11)
#6      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:282:5)
#7      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:217:7)
#8      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:475:9)
#9      PointerRouter._dispatch<…>
suztomo commented 4 years ago

What is in auth_provider.dart:88?

Can you share the entire code with line numbers?

valehasadli commented 4 years ago

What is in auth_provider.dart:88?

Can you share the entire code with line numbers?

image

suztomo commented 4 years ago

Remove these try and catch clause. They obscure stacktrace.

Share new stacktrace and source code with line number.

valehasadli commented 4 years ago

Remove these try and catch clause. They obscure stacktrace.

Share new stacktrace and source code with line number.

flutter: http://localhost:8000/api/mobile/auth/login
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: Invalid header field name, with 128
#0      IOClient.send (package:http/src/io_client.dart:62:7)
<asynchronous suspension>
#1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:176:38)
#2      BaseClient.post (package:http/src/base_client.dart:58:7)
#3      post.<anonymous closure> (package:http/http.dart:70:16)
#4      _withClient (package:http/http.dart:166:20)
#5      post (package:http/http.dart:69:5)
#6      AuthProvider.login (package:translationsolvermobile/providers/auth_provider.dart:49:42)
#7      _LoginScreenState._submitForm (package:translationsolvermobile/screens/login_screen.dart:44:7)
#8      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:779:19)
#9      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:862:36)
#10     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
#11     TapGestureRecognizer.handleTapUp (packag<…>
suztomo commented 4 years ago

Good. Now you know where to set a breakpoint.

Would you debug what it means? > Invalid header field name, with 128

valehasadli commented 4 years ago

Good. Now you know where to set a breakpoint.

Would you debug what it means? > Invalid header field name, with 128

I will check and back to you ASAP

valehasadli commented 4 years ago

Good. Now you know where to set a breakpoint.

Would you debug what it means? > Invalid header field name, with 128

image

valehasadli commented 4 years ago

@suztomo could you check, please?

suztomo commented 4 years ago

@nanophp Did you get the answer on what it means? > Invalid header field name, with 128

valehasadli commented 4 years ago

@nanophp Did you get the answer on what it means? > Invalid header field name, with 128

No, I didn't. I didn't get exactly, what does it mean.

suztomo commented 4 years ago

@nanophp By any change is that your server that sends the "Invalid header field name, with 128" message?

valehasadli commented 4 years ago

@nanophp By any change is that your server that sends the "Invalid header field name, with 128" message?

  • If so, nobody knows the meaning of the message except you. If you don't know, ask your teammates.
  • If the message is not from your server, would you find the Flutter source code that has the message?

It is not related to web service, I find the message.

image

suztomo commented 4 years ago

Nice. It's almost there. Can you check why does the $byte becomes 128? What's the content of the buffer? Are they all valid ascii characters?

valehasadli commented 4 years ago

Nice. It's almost there. Can you check why does the $byte becomes 128? What's the content of the buffer? Are they all valid ascii characters?

content is {"email":"valehasadli@gmail.com","password":"secret","device_name":"apple"} it is a ascii chars.

valehasadli commented 4 years ago

Nice. It's almost there. Can you check why does the $byte becomes 128? What's the content of the buffer? Are they all valid ascii characters?

@suztomo I'm trying where comes from this 128 byte.

valehasadli commented 4 years ago

@suztomo I just wanna ask you, if it is work with for example jsonplaceholder

final http.Response response = await http.post(
      'https://jsonplaceholder.typicode.com/albums',
      headers: <String, String>{
        'Content-Type': 'application/json; charset=UTF-8',
      },
      body: jsonEncode(<String, String>{
        'title': 'title1111',
      }),
    );

for example, this piece of code works fine and there is no problem. If we say maybe it is a related back-end app, why react app or postman or browser work true?

valehasadli commented 4 years ago

@suztomo It is the related back-end application, I don't mind it is HTTP package issue. Thanks for your support.

valehasadli commented 4 years ago

I will write an explanation of what happening in the app, and what is the exact problem into back-end application.

suztomo commented 4 years ago

Glad to hear you identified the problem. Looking forward to hearing why Dart http library complained “128”.

cdzc commented 4 years ago

I have the same problem:

[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: Invalid header field name, with 44

final http.Response response = await http.get(
  url,
  headers: <String,String>{
    HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
    HttpHeaders.authorizationHeader:"Bearer " +token,
   },
);
print('response=' + response.body);
D-sense commented 4 years ago

I was having the same issue lately. The Problem is in the Headers as pointed out by the @valehasadli @suztomo. This is definitely a Backend issue; cross-check your Response Headers' fields such as 'Content-Type', 'Bearer', etc. In my case, it was 'Bearer'; I had space right after 'Bearer' (like this: "Bearer "), which http.get could not parse, thus led to the Exception.

valehasadli commented 4 years ago

I was having the same issue lately. The Problem is in the Headers as pointed out by the @valehasadli @suztomo. This is definitely a Backend issue; cross-check your Response Headers' fields such as 'Content-Type', 'Bearer', etc. In my case, it was 'Bearer'; I had space right after 'Bearer' (like this: "Bearer "), which http.get could not parse, thus led to the Exception.

Could you share an exact example of your code before and after version?

D-sense commented 4 years ago

@valehasadli, I didn't really do anything with the Flutter part. I had to modify a snippet in the Backend which is written in Go/Golang. Basically, where I was renewing/regenerating the token and injecting it back to the Response Headers, I mistakenly added a space after 'Bearer' as explained above. So each time Dart makes a GET request to the backend, it would bump into "Bearer ", instead of "Bearer", and it would not be able to parse it. As a result, the exception was thrown.

valehasadli commented 4 years ago

@valehasadli, I didn't really do anything with the Flutter part. I had to modify a snippet in the Backend which is written in Go/Golang. Basically, where I was renewing/regenerating the token and injecting it back to the Response Headers, I mistakenly added a space after 'Bearer' as explained above. So each time Dart makes a GET request to the backend, it would bump into "Bearer ", instead of "Bearer", and it would not be able to parse it. As a result, the exception was thrown.

Yes, you’re quite right, the problem was related to back-end application docker configurations. Thanks for your sharing.