Skip to content

Prevent encoding query parameters #1445

Closed

Description

@xeinebiu

New Issue Checklist

  • I have searched for a similar issue in the project and found none
dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.4
  json_annotation: ^4.4.0
  dio: ^4.0.4

Issue Description and Steps

https://github.com/flutterchina/dio/blob/develop/dio/lib/src/options.dart#L545

The above code always does the encoding of query parameters by using + instead of spaces. The issue is, some servers do not understand the +, instead they use %20.

Tried to manually encode the query paramater value but then it ends up to duplicated encoding.

  • How to prevent encoding or provive a Query Parameter encoder to support this case ?
// Current (Term=Hello World)
baseUrl/search?term=HELLO+WORLD

Expected (Term=Hello World)
// baseUrl/search?term=HELLO%20WORLD

Activity

  1. xeinebiu commented on Mar 16, 2022

    @xeinebiu
    Author

    Currently using the below workaround.

    class EncodingInterceptor extends Interceptor {
      @override
      void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
        if (options.queryParameters.isEmpty) {
          super.onRequest(options, handler);
          return;
        }
    
        final queryParams = _getQueryParams(options.queryParameters);
        handler.next(
          options.copyWith(
            path: _getNormalizedUrl(options.path, queryParams),
            queryParameters: Map.from({}),
          ),
        );
      }
    
      String _getNormalizedUrl(String baseUrl, String queryParams) {
        if (baseUrl.contains("?")) {
          return baseUrl + "&$queryParams";
        } else {
          return baseUrl + "?$queryParams";
        }
      }
    
      String _getQueryParams(Map<String, dynamic> map) {
        String result = "";
        map.forEach((key, value) {
          result += "$key=${Uri.encodeComponent(value)}&";
        });
        return result;
      }
    }

    https://github.com/flutterchina/dio/blob/develop/dio/lib/src/transformer.dart#L45
    Can be fixed by using Uri.encodeComponent(value) instead.

  2. minhdangoz commented on Sep 16, 2022

    @minhdangoz

    Currently using the below workaround.

    class EncodingInterceptor extends Interceptor {
      @override
      void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
        if (options.queryParameters.isEmpty) {
          super.onRequest(options, handler);
          return;
        }
    
        final queryParams = _getQueryParams(options.queryParameters);
        handler.next(
          options.copyWith(
            path: _getNormalizedUrl(options.path, queryParams),
            queryParameters: Map.from({}),
          ),
        );
      }
    
      String _getNormalizedUrl(String baseUrl, String queryParams) {
        if (baseUrl.contains("?")) {
          return baseUrl + "&$queryParams";
        } else {
          return baseUrl + "?$queryParams";
        }
      }
    
      String _getQueryParams(Map<String, dynamic> map) {
        String result = "";
        map.forEach((key, value) {
          result += "$key=${Uri.encodeComponent(value)}&";
        });
        return result;
      }
    }

    https://github.com/flutterchina/dio/blob/develop/dio/lib/src/transformer.dart#L45 Can be fixed by using Uri.encodeComponent(value) instead.

    Thanks, it works with me

  3. mb180594b commented on Nov 24, 2022

    @mb180594b

    Currently using the below workaround.

    class EncodingInterceptor extends Interceptor {
      @override
      void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
        if (options.queryParameters.isEmpty) {
          super.onRequest(options, handler);
          return;
        }
    
        final queryParams = _getQueryParams(options.queryParameters);
        handler.next(
          options.copyWith(
            path: _getNormalizedUrl(options.path, queryParams),
            queryParameters: Map.from({}),
          ),
        );
      }
    
      String _getNormalizedUrl(String baseUrl, String queryParams) {
        if (baseUrl.contains("?")) {
          return baseUrl + "&$queryParams";
        } else {
          return baseUrl + "?$queryParams";
        }
      }
    
      String _getQueryParams(Map<String, dynamic> map) {
        String result = "";
        map.forEach((key, value) {
          result += "$key=${Uri.encodeComponent(value)}&";
        });
        return result;
      }
    }

    https://github.com/flutterchina/dio/blob/develop/dio/lib/src/transformer.dart#L45 Can be fixed by using Uri.encodeComponent(value) instead.

    I suggest you this change to avoid errors on the qp's types sent:

    String _getQueryParams(Map<String, dynamic> map) {
        String result = "";
        map.forEach((key, value) {
          result += value.runtimeType == String
              ? "$key=${Uri.encodeComponent(value)}&"
              : "$key=$value&";
        });
        return result;
      }
    
  4. AlexV525 commented on Dec 15, 2022

    @AlexV525
    Member

    Hi everyone. According to Uri.encodeQueryComponent that is used in Transformer.urlEncodeMap, it's the right choice of the API. But I also want to test if I can provide another solution to change the code base:

    Try to replace:
    https://github.com/flutterchina/dio/blob/9040bde4a07ffe4e201e4ec014242a16eb69d926/dio/lib/src/options.dart#L545-L550

    To this:

    // Normalize the url.
    return Uri.parse(url)
        .replace(queryParameters: queryParameters)
        .normalizePath();

    This will drop the usage of the ListFormat, but please let me know if it works.

  5. lucavenir commented on Jan 18, 2024

    @lucavenir

    This is completed because... there's a way to avoid encoding query parameters without the above workaround?

    The above workaround doesn't work for me. The parameters still gets encoded. Aka I want to send a query param like so:

    ?param=auth0|someId
    

    But even if I explicitly overwrite the above without encoding I still get

    ?param=auth0%7CsomeId
    

    Which is pretty annoying. I have no other interceptors implemented / connected.

  6. intraector commented on Feb 10, 2025

    @intraector

    Well, as it turns out, the only thing I had to do is just trim() the query. Works just fine.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions