http icon indicating copy to clipboard operation
http copied to clipboard

HTTP request results in exception when body is not read by the server.

Open joeyw7 opened this issue 5 years ago • 6 comments

version: 0.12.1 If I sent a post/put requests with a jsonBody and the server responds without reading the body, then it throws an unhandled exception

E/flutter ( 3983): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 
E/flutter ( 3983): #0      IOClient.send (package:http/src/io_client.dart:62:7)
E/flutter ( 3983): <asynchronous suspension>
E/flutter ( 3983): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:176:38)
E/flutter ( 3983): #2      BaseClient.put (package:http/src/base_client.dart:81:7)
E/flutter ( 3983): #3      put.<anonymous closure> (package:http/http.dart:94:16)
E/flutter ( 3983): #4      _withClient (package:http/http.dart:166:20)
E/flutter ( 3983): #5      put (package:http/http.dart:93:5)

Here is how I reproduced the problem. In my flutter app, I have 2 buttons that will send requests to the servers. image

In my flask servers,

@app.route('/test-post', methods=['POST'])
def test_post():
   # print(request.get_json())
    return make_response('tested', 200) 

@app.route('/test-put', methods=['PUT'])
def test_put():
   # print(request.get_json())
    return make_response('tested', 200) 

When the request is sent, it will result in the above exception. But if the "request.get_json()" or "request.get_data()" is called in flask, it will work just fine. I am guessing the server terminated the input stream when it sends back the response, which caused the error.

joeyw7 avatar Jun 29 '20 05:06 joeyw7

I was experiencing this issue and I was lost. This workaround saved my day. I'm using the same technologies as you, Flutter + Flask.

koyadovic avatar Oct 25 '20 17:10 koyadovic

@koyadovic You can try using dio package instead, I haven't use it but it is recommended by a lot of people. https://pub.dev/packages/dio

joeyw7 avatar Oct 26 '20 05:10 joeyw7

I had this request today. The most frustrated part of this error is that there is no expection message. Flask would return a 200 despite the exception, which makes identifying the issue more difficult.

hyiip avatar Aug 25 '21 21:08 hyiip

I can't reproduce this. Version 0.12.1 seems incompatible with recent Dart SDKs due to a minor breaking change in the SDK, however when I fix that or use an older Dart SDK and try making a post request to a (Dart) server which response with OK but does not read the body I get no exception.

Can somebody post a complete reproduction?

I tried with

//server.dart
import 'dart:io';

void main() async {
  var server = await HttpServer.bind('localhost', 8080);
  await for (var request in server) {
    await (request.response..statusCode = HttpStatus.ok).close();
  }
}
// client.dart
import 'package:http/http.dart' as http;

void main() async {
  var client = http.Client();
  await client.post(Uri.http('localhost:8080', ''), body: 'something');
  print('Done');
  client.close();
}

natebosch avatar Aug 27 '21 00:08 natebosch

@natebosch I tried to reproduce the issue with minimal code with Dart frontend and Python backend, see if it is useful.

// client.dart
import 'package:http/http.dart' as http;

void main() async {
  var client = http.Client();
  await client.post(Uri.http('192.168.1.245:8080', 'test'), body: 'something');
  print('first request done');
  await client.post(Uri.http('192.168.1.245:8080', 'test'), body: 'something');
  print('second request done');
  client.close();
}
from flask import Flask, request

app = Flask(__name__)

@app.route("/test", methods=["POST"])
def test():
    return "this is a return", 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080,debug=True)

The first request is fine, but adding second request gives an exception. If I run the Dart code directly, I get the exception Connection closed before full header was received.

first request done
Unhandled exception:
Connection closed before full header was received
#0      IOClient.send (package:http/src/io_client.dart:61:7)
<asynchronous suspension>
#1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:32)
<asynchronous suspension>
#2      main (file:///C:/Users/User/AndroidStudioProjects/homie/test/client.dart:7:3)
<asynchronous suspension>

But if I run the client side code on a Flutter environment, the exception reason somehow get compressed and not shown in the debugger.

I/flutter (20429): first request done
E/flutter (20429): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: 
E/flutter (20429): #0      IOClient.send (package:http/src/io_client.dart:61:7)
E/flutter (20429): <asynchronous suspension>
E/flutter (20429): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:32)
E/flutter (20429): <asynchronous suspension>
E/flutter (20429): #2      main (package:homie/main.dart:7:3)
E/flutter (20429): <asynchronous suspension>
E/flutter (20429): 

Back to the exception itself. If I add request.body in Flask like the following:

@app.route("/test", methods=["POST"])
def test():
    request.data
    return "this is a return", 200

Then on the client side everything works fine. Not sure how to reproduce the error using a Dart server.

hyiip avatar Aug 30 '21 19:08 hyiip

Thanks for the workaround joey! You saved me from a lot of trouble.

humza-ahmed235 avatar Oct 29 '21 07:10 humza-ahmed235

I'm not able to reproduce this with multiple unread POST bodies to either a Dart or Python+Flask server.

If this is still a problem for someone, please add a comment with the Dart SDK version and the code you are using.

natebosch avatar Sep 08 '22 19:09 natebosch