Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api request fail - please set a proper content-type in the request #2338

Closed
qeepcologne opened this issue Dec 3, 2024 · 7 comments
Closed

Comments

@qeepcologne
Copy link

qeepcologne commented Dec 3, 2024

Package

dio

Version

5.7.0

Operating-System

Android

Adapter

Default Dio

Output of flutter doctor -v

[✓] Flutter (Channel stable, 3.24.5, on Ubuntu Plucky Puffin (development branch) 6.11.0-9-generic, locale en_DE.UTF-8)
    • Flutter version 3.24.5 on channel stable at /home/bwahlen/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision dec2ee5c1f (3 weeks ago), 2024-11-13 11:13:06 -0800
    • Engine revision a18df97ca5
    • Dart version 3.5.4
    • DevTools version 2.37.3

[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
    • Android SDK at /home/bwahlen/android-sdk-linux
    • Platform android-Baklava, build-tools 35.0.0
    • ANDROID_HOME = /home/bwahlen/android-sdk-linux
    • Java binary at: /usr/lib/jvm/temurin-23-jdk-amd64/bin/java
    • Java version OpenJDK Runtime Environment Temurin-23.0.1+11 (build 23.0.1+11)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Android Studio (version 2024.3)
    • Android Studio at /home/bwahlen/android-studio
    • Flutter plugin version 83.0.4
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version openjdk version "21.0.5" 2024-10-15

[✓] Connected device (2 available)
    • sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64    • Android 15 (API 35) (emulator)
    • Chrome (web)                 • chrome        • web-javascript • Google Chrome 131.0.6778.85

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Dart Version

3.5.4

Steps to Reproduce

we are doing qutite simple api requests e.g.

  final response = await api.post("/user-profile/update.json", data: myProfile);

or

    final response = await api.post("/pushnotification-fcm/register.json", data: {
      "message_types": enabledFcmTypesStr,
      "token": fcmToken,
      "platform": platform().name,
      "environment": ApiConfig.debug ? "dev" : "live",
      "operation": "register"
    });

Expected Result

everything worked fine with dio 5.6.0 or lower.
Expected the same with 5.7.0

Actual Result

requests fail with:

[🔔 Dio] User cannot be used to imply a default content-type, please set a proper content-type in the request.
         #0      ImplyContentTypeInterceptor.onRequest (package:dio/src/interceptors/imply_content_type.dart:33:22)
         #1      DioMixin.fetch.requestInterceptorWrapper.<anonymous closure>.<anonymous closure> (package:dio/src/dio_mixin.dart:398:17)
         #2      new Future.<anonymous closure> (dart:async/future.dart:258:40)
         #3      Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
         #4      _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
         #5      _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
         #6      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

btw content type is set in interceptor:

final api = Dio(_baseOptions)..interceptors.addAll([_requestHeaders(), _responseErrors()]);

Interceptor _requestHeaders({bool login = false}) =>
    InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      if (!login && GlobalState.prefs.get(pref_keys.sessionId) == null) {
        throw LoginRequiredException("sessionId missing - login required", requestOptions: options);
      }
      //could not add to baseOptions because the sessionId may not be there when base options are created
      options.headers.addAll(apiHeaders(method: options.method, login: login));
      return handler.next(options);
    });
    
    Map<String, String> apiHeaders({String? method, bool login = false}) => {
      HttpHeaders.acceptLanguageHeader: GlobalState.localeHeader,
      if (!kIsWeb) HttpHeaders.userAgentHeader: userAgent(),
      CustomHeaders.clientKey: ApiConfig.apiKey(),
      if (!login) CustomHeaders.userKey: GlobalState.prefs.getString(pref_keys.sessionId)!,
      if (!login) HttpHeaders.cookieHeader: _cookieHeaderValue(),
      if (method == "POST") HttpHeaders.contentTypeHeader: ContentType.json.toString()
    };
@qeepcologne qeepcologne added h: need triage This issue needs to be categorized s: bug Something isn't working labels Dec 3, 2024
@AlexV525
Copy link
Member

AlexV525 commented Dec 3, 2024

The log has told you that User was used in the payload without a proper conversion so the request was failed.

@AlexV525 AlexV525 closed this as not planned Won't fix, can't repro, duplicate, stale Dec 3, 2024
@AlexV525 AlexV525 added i: not reading documents and removed h: need triage This issue needs to be categorized s: bug Something isn't working labels Dec 3, 2024
@qeepcologne
Copy link
Author

The log has told you that User was used in the payload without a proper conversion so the request was failed.

1.) User is @JsonSerializable and has toJson method
2.) that' not the cause - this is why i add the second request, which using just plain json map
3.) content type is added in interceptor (see above)

!! everything works with 5.6.0 and below. There must be some breaking change, that is not documented, i read the migration guide, no change after 5.0.0 mentioned there

@AlexV525
Copy link
Member

AlexV525 commented Dec 3, 2024

Could you split a minimal reproducible example?

@qeepcologne
Copy link
Author

i add removeImplyContentTypeInterceptor and everything works like before (because i add my own content type header to post requests).
Problem is the order of the interceptors: ImplyContentTypeInterceptor runs if options.contentType == null, but own interceptor setting the content type is added after ImplyContentTypeInterceptor.

@AlexV525
Copy link
Member

AlexV525 commented Dec 3, 2024

The imply interceptor only logs when no content-type and will not manipulate any of your payload.

@qeepcologne
Copy link
Author

exactly in my case the problem is that ImplyContentTypeInterceptor runs before content type is set in my own interceptor.
But you are right, these data is recognized as object and not as List, Map or String as needed:
a.) for the @JsonSerializable() objects, it helps adding toJson()
´´´
response = await api.post("/newslettersetting/update.json", data: ResponseEmailNotifications(settings).toJson());
´´´
instead of
´´´
response = await api.post("/newslettersetting/update.json", data: ResponseEmailNotifications(settings));
´´´

b.) for some other cases switch inside data break the type

@AlexV525
Copy link
Member

AlexV525 commented Dec 3, 2024

You should always define your type in your interceptors, which is why the imply one runs first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants