http icon indicating copy to clipboard operation
http copied to clipboard

Remove charset from "Content-Type" header

Open Pandazaur opened this issue 7 years ago • 17 comments

Hello,

I need to post some data to a distant API. But it looks like the API wants Content-Type: application/json but I'm sending a Content-Type: application/json; charset=utf-8.

I forced the headers:

Map<String, String> headers = {
            HttpHeaders.AUTHORIZATION: 'Bearer ${this._token}',
            HttpHeaders.CONTENT_TYPE: 'application/json'
};

but keep sending with the charset. Is there a possibility to remove it from the Content Typeheader ?

Thanks

Pandazaur avatar Jul 19 '18 20:07 Pandazaur

Looks like charset ("encoding") is always added on Content-Type in case it's not set: https://github.com/dart-lang/http/blob/master/lib/src/request.dart#L84-L92

For good measure I checked with the RFCs and it seems the "parameter" part of the Content-Type value is either mandatory or optional depending on the particular MIME type/subtype: https://tools.ietf.org/html/rfc2045#section-5

As far as I can tell the 'application/json' MIME type does explicitly not define a "charset" parameter: https://www.iana.org/assignments/media-types/application/json

Ultimately this points to the http package being buggy. I don't think it's valid to blindly add parameters to just any MIME type. In fact, while probably done with good intentions, silently adding anything should probably be avoided.

ghost avatar Aug 23 '18 11:08 ghost

Work-around: Set the body first (this sets default headers), then set the headers.

jheyne avatar Feb 15 '19 17:02 jheyne

I have the same problem, however the above solution did not work in my case.

jefioliveira avatar Feb 22 '19 22:02 jefioliveira

For clarity, this is what worked for me: Request request = new Request('POST', Uri.parse(url)); request.body = body; request.headers['content-type'] = 'text/xml'; request.headers['accept'] = 'text/xml';

jheyne avatar Feb 23 '19 01:02 jheyne

I encountered the same issue, but @jheyne workaround didn't work for me.

We should be able to write request.encoding = null.

aloisdeniel avatar Jul 01 '19 05:07 aloisdeniel

Good afternoon,

I have the same problem.

The lib is automatically placing charset = utf-8 in the request header, so I'm having trouble consuming some REST WebServices, making it impossible to use it.

The issue is already open for one year.

Is there no solution to such a problem?

Thank you.

Cristian Regazzo

cmregazzo avatar Jul 16 '19 19:07 cmregazzo

Has anyone solved this yet?

It seems to be more of a problem when there encoding more complex types such as

class MyClass { ClassOne class1; ClassTwo class2; }

I've tried jsonEncode, I've used the JSONSerializable package, setting the body before headers, just as @jheyne mentioned. I don't understand why the HttpClient encodes to UTF-8 by default. Either way, life is very difficult right now. I've even added UTF-8 encoding to my .NET server and still nothing :(

Marc

Dudecor3 avatar Jul 16 '19 21:07 Dudecor3

Has anybody found a solution to this yet? I'm running into the same problem with my REST endpoint refusing to accept my requests because it doesn't expect the charset property to be set.

For now I have a local solution by copying the Package locally and modifying lib/src/request.dart to remove the lines that add charset if it's not there: (based on @cskau-g 's comment earlier)

request.dart

91  set body(String value) {
92    bodyBytes = encoding.encode(value);
93    var contentType = _contentType;
94    if (contentType == null) {
95      _contentType = MediaType('text', 'plain', {'charset': encoding.name});
-     } else if (!contentType.parameters.containsKey('charset')) {
-       _contentType = contentType.change(parameters: {'charset': encoding.name});
96    }
97  }

You can find that code excerpt at https://github.com/dart-lang/http/blob/master/lib/src/request.dart#L84-L92

@jefioliveira tried to made a pull request for a similar change but it was understandably denied because a lot of applications probably rely on the current auto-addition of charset. It's been six months since then.

Would it be possible to just add an additional optional parameter to the Request class that would tell it not to add charset?

Multiamory avatar Jan 27 '20 04:01 Multiamory

@jheyne solution worked for me.

vikalpnagar avatar Feb 28 '20 18:02 vikalpnagar

I had problem with the API server not accepting "charset". @jheyne's solution worked perfectly.

AndreasLymalmSigma avatar Jun 22 '20 07:06 AndreasLymalmSigma

@jheyne's answer worked for me.

This is my code.

    import 'package:http/http.dart';

    final String url = "your api url";

    try {
      final httpClient = HttpClient();
      final request = await httpClient.postUrl(Uri.parse(url));
      // headers
      request.headers.set('Authorization', 'Bearer $AuthToken');
      request.headers.contentType = new ContentType("application", "json");
      // body
      request.add(
        utf8.encode(
          jsonEncode(
            {
              'somebody': somebody,
            },
          ),
        ),
      );

      final response = await request.close();

      if (response.statusCode == 200) {
        final responseBody = await response.transform(utf8.decoder).join();
        final result = Model.fromJson(json.decode(responseBody));
      }
    } on TimeoutException catch (_) {
      //print
    } on SocketException catch (_) {
      //print
    }

shin avatar Aug 13 '20 01:08 shin

This is a complete non sense : why is the charset added even if we provide the content-type ? The user input should override the default values, not the opposite !

monisnap-julien avatar Sep 09 '20 13:09 monisnap-julien

Are there any updates regarding this topic? Has anyone managed to remove the 'charset=utf8' from the http header or found another solution? My backend also won't accept the request if the charset is specified.

Please specify 'application/vnd.api+json' instead of 'application/vnd.api+json; charset=utf-8' for the Content-Type header value.

Also I use Json Api Specification for Flutter. I cannot set the body first like @jheyne mentioned because the library makes the request.

final httpHandler = LoggingHttpHandler(DartHttp(httpClient),
        onRequest: (r) => print('${r.method} ${r.uri} ${r.headers}'),
        onResponse: (r) => print('${r.statusCode} ${r.body}'));

final client = JsonApiClient(httpHandler);

var headers = {
      'Authorization': 'Bearer $jwtToken',
      'Content-Type': 'application/vnd.api+json'
};

client.fetchResourceAt(Uri.parse('$urlTesting$urlPath/code/$invitationCodeString'),headers: headers);

frozen-syntax avatar Oct 27 '20 16:10 frozen-syntax

@snowLimit I faced the same issues and decided to use this library https://pub.dev/packages/dio. It's very similar but more flexible and has a lot of interesting features 😉

monisnap-julien avatar Oct 27 '20 17:10 monisnap-julien

@jheyne's answer worked for me.

This is my code.

import 'package:http/http.dart';

final String url = "your api url";

try {
  final httpClient = HttpClient();
  final request = await httpClient.postUrl(Uri.parse(url));
  // headers
  request.headers.set('Authorization', 'Bearer $AuthToken');
  request.headers.contentType = new ContentType("application", "json");
  // body
  request.add(
    utf8.encode(
      jsonEncode(
        {
          'somebody': somebody,
        },
      ),
    ),
  );

  final response = await request.close();

  if (response.statusCode == 200) {
    final responseBody = await response.transform(utf8.decoder).join();
    final result = Model.fromJson(json.decode(responseBody));
  }
} on TimeoutException catch (_) {
  //print
} on SocketException catch (_) {
  //print
}

it works for me

Erarshad avatar Mar 24 '21 13:03 Erarshad

this is ridiculous migrated to Dio

martipello avatar Jul 13 '21 08:07 martipello

this is ridiculous migrated to Dio

Unbelievable that you'd have to pick a library over the langs native HTTP client. I've never seen a language where the HTTP client is so bad.

Dud3core-webdev avatar Jul 13 '21 08:07 Dud3core-webdev

Has anything changed yet?

LeonManolo avatar Apr 19 '23 20:04 LeonManolo

@brianquinlan I think that this issue should be closed , current http package supports headers and with charsets.

I dont think charsets removal is beneficial.

Otherwise we can help adding more fields such as json , jsonwithnonCharset.

But it doesnt make sense.

seifibrahim32 avatar Apr 22 '23 11:04 seifibrahim32

It's possible to use Fetch API directly, if you are build for Web Platform only:

import 'dart:js' as js;


var options = js.JsObject(js.context['Object']);
var headers = js.JsObject(js.context['Object']);
headers['Content-Type'] = 'application/json';
options['method'] = 'POST';
options['headers'] = headers;
options['body'] = jsonEncode(<String, String>{
  'name': 'Flutter',
});

var result = await js.context.callMethod(
  'fetch',
  [
    'https://some.place.com/foo/bar',
    options
  ],
);

But colleague suggest better way — https://pub.dev/packages/dio

Result looks like:

final dio = Dio();

final response = await dio.post(
  'https://some.place.com/foo/bar',
  data: jsonEncode(<String, String>{
    'name': 'Flutter',
  }),
  options: Options(
    headers: {},
    contentType: 'application/json',
  ),
);

log(jsonEncode(response.data));

astnt avatar Jun 12 '23 15:06 astnt

This seems to be working as designed and documented.

If you want to assign set the body without setting the Content-Type header implicitly, can't you just assign your data to bodyBytes directly e.g.

final request = Request('GET', myUrl)
  ..bodyBytes = utf8.encode(myJson)
  ..headers['content-type'] = 'application/json';

?

If that is the case, please let me know and I will update the documentation to demonstrate this pattern.

brianquinlan avatar Jul 13 '23 20:07 brianquinlan

this is ridiculous migrated to Dio

Unbelievable that you'd have to pick a library over the langs native HTTP client. I've never seen a language where the HTTP client is so bad.

Let's try to follow the code of conduct and be kind to each other.

brianquinlan avatar Jul 13 '23 20:07 brianquinlan

@snowLimit I faced the same issues and decided to use this library https://pub.dev/packages/dio. It's very similar but more flexible and has a lot of cool features😉

I did the same thing my friend, Dio is wasome. As soon as I find time I intend to submit a correction to this lib again, add an optional parameter or something like that.

I understand that the solution was denied because I inadequately described the problem, but I intend to redo it soon.

jefioliveira avatar Jul 16 '23 03:07 jefioliveira

Is there any more feedback on this? Does the pattern suggested in https://github.com/dart-lang/http/issues/184#issuecomment-1634877777 fix the issue?

brianquinlan avatar Aug 15 '23 23:08 brianquinlan