get request params URI encoding · Issue #1111 · axios/axios · GitHub
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

get request params URI encoding #1111

Closed
GuramDuka opened this issue Oct 2, 2017 · 18 comments
Closed

get request params URI encoding #1111

GuramDuka opened this issue Oct 2, 2017 · 18 comments

Comments

@GuramDuka
Copy link

#### Summary

function encode(val) in buildURL.js
encodes spaces as '+'
this is wrong, because not all http servers decodes '+'

I comment line out and it working for me.

function encode(val) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
// replace(/%20/g, '+').
replace(/%5B/gi, '[').
replace(/%5D/gi, ']');
}

#### Context

  • axios version: e.g.: v0.16.0
  • Environment: e.g.: node v6.9.4, chrome 54, windows 7
@rolfb
Copy link

rolfb commented Oct 6, 2017

Can you have provide an example of the data that failed encoding before you commented this line out?

@GuramDuka
Copy link
Author

view : {
type : "Номенклатура",
parent : '00000000-0000-0000-0000-000000000000',
groups : true,
elements : false,
filter : 'Таблица.ЭтоГруппа ИЛИ Таблица.ОстатокОбщий <> 0'
}

spaces in filter value
string is mix of utf-8 cyrillic and latin symbols

@rolfb
Copy link

rolfb commented Oct 6, 2017

Did the issue only occur in the filter value?

Can you provide the final URL before and after commenting out the line?

@GuramDuka
Copy link
Author

BEFORE:
http://localhost:3000/api/backend?r=%7B%22r%22:%7B%22type%22:%22%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D0%B0%22,%22parent%22:%2200000000-0000-0000-0000-000000000000%22,%22groups%22:true,%22elements%22:false,%22filter%22:%22%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0.%D0%AD%D1%82%D0%BE%D0%93%D1%80%D1%83%D0%BF%D0%BF%D0%B0+%D0%98%D0%9B%D0%98+%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0.%D0%9E%D1%81%D1%82%D0%B0%D1%82%D0%BE%D0%BA%D0%9E%D0%B1%D1%89%D0%B8%D0%B9+%3C%3E+0%22,%22cols%22:[%22%D0%9A%D0%BE%D0%B4%22,%22%D0%9D%D0%B0%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%22,%22%D0%90%D1%80%D1%82%D0%B8%D0%BA%D1%83%D0%BB%22,%22%D0%9F%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%22,%22%D0%9E%D1%81%D1%82%D0%B0%D1%82%D0%BE%D0%BA%D0%9E%D0%B1%D1%89%D0%B8%D0%B9%22,%22%D0%9D%D0%B0%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%9F%D0%BE%D0%BB%D0%BD%D0%BE%D0%B5%22,%22%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D1%8B%22,%22%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D1%8B%D0%92%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B5HTML%22]%7D,%22m%22:%22dict%22,%22f%22:%22list%22%7D

AFTER:
http://localhost:3000/api/backend?r=%7B%22r%22:%7B%22type%22:%22%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D0%B0%22,%22parent%22:%2200000000-0000-0000-0000-000000000000%22,%22groups%22:true,%22elements%22:false,%22filter%22:%22%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0.%D0%AD%D1%82%D0%BE%D0%93%D1%80%D1%83%D0%BF%D0%BF%D0%B0%20%D0%98%D0%9B%D0%98%20%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0.%D0%9E%D1%81%D1%82%D0%B0%D1%82%D0%BE%D0%BA%D0%9E%D0%B1%D1%89%D0%B8%D0%B9%20%3C%3E%200%22,%22cols%22:[%22%D0%9A%D0%BE%D0%B4%22,%22%D0%9D%D0%B0%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%22,%22%D0%90%D1%80%D1%82%D0%B8%D0%BA%D1%83%D0%BB%22,%22%D0%9F%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%22,%22%D0%9E%D1%81%D1%82%D0%B0%D1%82%D0%BE%D0%BA%D0%9E%D0%B1%D1%89%D0%B8%D0%B9%22,%22%D0%9D%D0%B0%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%9F%D0%BE%D0%BB%D0%BD%D0%BE%D0%B5%22,%22%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D1%8B%22,%22%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%D0%9D%D0%BE%D0%BC%D0%B5%D0%BD%D0%BA%D0%BB%D0%B0%D1%82%D1%83%D1%80%D1%8B%D0%92%D0%A4%D0%BE%D1%80%D0%BC%D0%B0%D1%82%D0%B5HTML%22]%7D,%22m%22:%22dict%22,%22f%22:%22list%22%7D

@rolfb
Copy link

rolfb commented Oct 6, 2017

Thanks. Do you have any information on the server that didn't accept the + character as a space?

@GuramDuka
Copy link
Author

Server: Apache/2.4.27 (Win64) OpenSSL/1.1.0f

I apologize for the fact that unwittingly misled you. The problem is not the HTTP server. The problem is in the app's library. Not all libraries applications follow the recommendations www.w3.org. It's ironic, but the variant with %2B instead of + , allows for higher compatibility with all libraries.

@rolfb
Copy link

rolfb commented Oct 6, 2017

I assume that you mean %20?

Looking at the RFC-3986 standard for URIs there's the following information in 2.3:

      reserved    = gen-delims / sub-delims

      gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

      sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
                  / "*" / "+" / "," / ";" / "="

gen-delims being reserved in the path of the URI and sub-delims being reserved after the ? in params, and in a later standard [ and ] were added. So + shouldn't be an issue as it's within the standard, but I can clearly see that it is.

@GuramDuka
Copy link
Author

I assume that you mean %20?
Yes, I was wrong.

@davidlaym
Copy link

davidlaym commented Jul 12, 2018

I'm facing a similar issue in which I'm making a GET request to a legacy server that doesn't accept + as space and needs %20. Is there a way to configure the encoding or skip it?

@davidlaym
Copy link

davidlaym commented Jul 12, 2018

To answer my own question, I found out about paramsSerializer in the config parameter and then found the default implementation of paramsSerializer in the code

function encode(val) {
return encodeURIComponent(val).
replace(/%40/gi, '@').
replace(/%3A/gi, ':').
replace(/%24/g, '$').
replace(/%2C/gi, ',').
replace(/%20/g, '+').
replace(/%5B/gi, '[').
replace(/%5D/gi, ']');

and

var parts = [];
utils.forEach(params, function serialize(val, key) {
if (val === null || typeof val === 'undefined') {
return;
}
if (utils.isArray(val)) {
key = key + '[]';
} else {
val = [val];
}
utils.forEach(val, function parseValue(v) {
if (utils.isDate(v)) {
v = v.toISOString();
} else if (utils.isObject(v)) {
v = JSON.stringify(v);
}
parts.push(encode(key) + '=' + encode(v));
});
});
serializedParams = parts.join('&');

This led me to implement my own version overriding the encoder and bypassing some of the util functions as I'm working on TS and nodejs and I can use some built in alternatives:

function encode(val: any) {
  return encodeURIComponent(val)
    .replace(/%40/gi, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']');
}

function customSerializer(params: any): string {
  return Object.keys(params)
    .map((key: any) => {
      var val: any = params[key];
      if (val === null || typeof val === 'undefined') {
        return;
      }
      var keyName = key;
      if (Array.isArray(val)) {
        keyName = key + '[]';
      } else {
        val = [val];
      }
      return val
        .map((v: any) => {
          if (Object.prototype.toString.call(v) === '[object Date]') {
            v = v.toISOString();
          } else if (v !== null && typeof v === 'object') {
            v = JSON.stringify(v);
          }
          return encode(key) + '=' + encode(v);
        })
        .join('&');
    })
    .join('&');
}

@drakej
Copy link

drakej commented Apr 19, 2019

You're violating the spec here, at least current ones from what I see. Axios broke what was working in jQuery so I think it's safe to say that you should use %20 as it's most compatible regardless of what old specs say about + being used for URLs.

https://stackoverflow.com/questions/2678551/when-to-encode-space-to-plus-or-20

@drakej
Copy link

drakej commented Apr 19, 2019

I just realized that you set this and it's not Axios itself. Sorry my misunderstanding in how things work. You can ignore my comment, and really the issue is Qs.stringify.

Since you can set a custom serializer, this issue isn't Axios anyways. Sorry if I wasted your time on this. I think you can actually close this as it's not an Axios bug at all.

@meteorlxy
Copy link

I guess %20 is , and %2B is +.

image

Is this a typo or intended?

replace(/%20/g, '+').

@k-kusumitha
Copy link

Same issue here

@CristianPinzaru
Copy link

Same issue with [ and ]...

@cambraca
Copy link

Created PR #2563 to fix this and other similar issues.

@jasonsaayman
Copy link
Member

On this I don't think this should be implement as mentioned previously if you'd like to use another format, you can set a custom paramsSerializer as follows:

axios.defaults.paramsSerializer: function(params) {
  // return a query string
}

Using the qs library:

axios.defaults.paramsSerializer: function(params) {
  return qs.stringify(params, { indices: false }); // param=value1&param=value2
}

@Cactusbone
Copy link

On this I don't think this should be implement as mentioned previously if you'd like to use another format, you can set a custom paramsSerializer as follows:

Indeed we can use a custom paramsSerializer to use RFC 3986, however I believe it should be the default, because latest web servers won't accept RFC 1738 encoded params, however old servers should accept RFC 3986 (at the very least the %20 encoding for spaces is backward compatible).

Using a custom paramsSerializer must be done every time we use axios, so it's quite error prone imo.

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

No branches or pull requests