55

I have angular application where i want to pass plus sign + in query string like:

http://localhost:3000/page?name=xyz+manwal

When I am hitting this URL its converting to:

http://localhost:3000/page?name=xyz%20manwal

Where %20 refer to space . How can I prevent this conversion?

Maxim Kuzmin
  • 2,574
  • 19
  • 24
Manwal
  • 23,450
  • 12
  • 63
  • 93
  • why do you need that? – Max Koretskyi Aug 01 '17 at 04:21
  • I want to use name value like `xyz+manwal` in given URL currently its saving `xyz manwal`. – Manwal Aug 01 '17 at 04:22
  • it's just URL, wherever you read it it should be correctly parsed as a plus, you can't use plus in the URL. Read [this](https://stackoverflow.com/questions/2678551/when-to-encode-space-to-plus-or-20) – Max Koretskyi Aug 01 '17 at 04:30
  • 1
    @Maximus I tried to decode and use it. I am getting space ` ` instead of +. There is an old version of website running which is on `.net` technology. There + sign is acceptable but not in new version which is in angular. So its like mandatory to follow same URL pattern in both. – Manwal Aug 03 '17 at 07:04
  • sorry, cant help there – Max Koretskyi Aug 03 '17 at 07:18
  • 1
    Use the hex code for a plus sign, as ``+`` is equivalent to ``%20`` in urls. – allo Aug 04 '17 at 09:32
  • @Manwal did the solution work for you ? – FAISAL Aug 11 '17 at 09:58

13 Answers13

45

You can override default angular encoding with adding Interceptor which fixes this:

import { HttpInterceptor, HttpRequest, HttpEvent, HttpHandler, HttpParams, HttpParameterCodec } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";

@Injectable()
export class EncodeHttpParamsInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const params = new HttpParams({encoder: new CustomEncoder(), fromString: req.params.toString()});
    return next.handle(req.clone({params}));
  }
}


class CustomEncoder implements HttpParameterCodec {
  encodeKey(key: string): string {
    return encodeURIComponent(key);
  }

  encodeValue(value: string): string {
    return encodeURIComponent(value);
  }

  decodeKey(key: string): string {
    return decodeURIComponent(key);
  }

  decodeValue(value: string): string {
    return decodeURIComponent(value);
  }
}

and declare it in providers section of in app.module.ts

providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: EncodeHttpParamsInterceptor,
      multi: true
    }
]
Stephen Turner
  • 7,125
  • 4
  • 51
  • 68
Piotr Korlaga
  • 3,338
  • 2
  • 19
  • 28
  • 2
    this creates a mess of double encoding – Toolkit Jun 07 '20 at 07:19
  • For reference: it is a bug, see https://github.com/angular/angular/issues/11058 – beat Mar 01 '21 at 10:44
  • The referenced CustomEncoder class can be found in https://github.com/angular/angular/issues/18261, which was written 21/10/2017 (Orestes) – qqtf May 19 '21 at 13:07
  • This solution worked for me. I can now keep '+' sign in url query param while sending request from Angular (8) to Java (8). It is not converting to " " or %2B – Surya Jun 07 '21 at 11:36
  • Same, this solution worked for me as well. UP – Dan Aug 17 '22 at 13:16
23

This ia a common problem. The + character is used by the URL to separate two words. In order to use the + character in the parameter values, you need to encode your parameter values before adding them as part of the URL. Javascript / TypeScript provide a encodeURI() function for that specific purpose.

URL encoding converts characters into a format that can be transmitted over the Internet. [w3Schools Reference]

Here is how you can fix this problem:

let encodedName = encodeURI('xyz+manwal');
let encodedURI = 'http://localhost:3000/page?name='+encodedName;

//.. OR using string interpolation
let encodedURI = `http://localhost:3000/page?name=${ encodedName }`;

In the same way, you can decode the parameters using decodeURI() method.

let decodedValue = decodeURI(encodedValue);
FAISAL
  • 33,618
  • 10
  • 97
  • 105
  • 1
    This solution is better, encoding before using in URL works well but. There are 3rd parties who generate links, which contain `+` sign. These URL were working well in the old version of the application which in is `c#`. But for us(New version of the application) in angular it's not even accepting `+` sign immediately converting `+` to `%20`. – Manwal Aug 11 '17 at 10:12
  • When I am serving angular with webpack its changing URL `+` into `%20`. I want to see `+` sign on URL. Where in other server in apache php not converting `+` into anything its same in URL. – Manwal Aug 30 '17 at 04:06
19

In Angular 5.2.7+ the "+" is replaced with space " " in a query string.

Here is the corresponding commit : fix(router): fix URL serialization

If you want to change this behaviour and replace the "+" with "%2B" you can create a custom url serializer and provide it in the AppModule providers.

import { DefaultUrlSerializer, UrlSerializer, UrlTree } from '@angular/router';

export default class CustomUrlSerializer implements UrlSerializer {
    private _defaultUrlSerializer: DefaultUrlSerializer = new DefaultUrlSerializer();

    parse(url: string): UrlTree {
        // Encode "+" to "%2B"
        url = url.replace(/\+/gi, '%2B');
        // Use the default serializer.
        return this._defaultUrlSerializer.parse(url);
    }

    serialize(tree: UrlTree): string {
        return this._defaultUrlSerializer.serialize(tree).replace(/\+/gi, '%2B');
    }
}

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule
    ],
    declarations: [
        AppComponent
    ],
    providers: [
        { provide: UrlSerializer, useClass: CustomUrlSerializer }
    ],

    entryComponents: [],
    bootstrap: [AppComponent]
})
export class AppModule {
}

http://localhost:3000/page?name=xyz+manwal

The URL will be converted to:

http://localhost:3000/page?name=xyz%2Bmanwal

Hope this will help.

abahet
  • 10,355
  • 4
  • 32
  • 23
10

In Angular v6.1.10, if you just need to fix the "+" sign encoding in one spot, this is what worked for me.

getPerson(data: Person) {

  const httpParams = new HttpParams({
    fromObject: {
      id: data.id,
      name: data.name,
      other: "xyz+manwal"
    }
  });

  // manually encode all "+" characters from the person details
  let url = BASE_URL + "/select?" + httpParams.toString().replace(/\+/gi, '%2B');

  return this.http.get(url);
}

I found if you try to replace the "+" signs when initializing the httpParams object it doesn't work. You have to do the replacement after converting httpParams to a string, as shown on this line:

let url = BASE_URL + "/select?" + httpParams.toString().replace(/\+/gi, '%2B');
Daniel Congrove
  • 3,519
  • 2
  • 35
  • 59
5

This is a quite common problem. You can pass it normally in application/x-www-form-urlencoded request. No other request will be able to correctly parse +. They will always parse it into %20 instead of %2B.

You would need to manually manipulate the query parameter, there are 2 ways:

  • Encode the parameter into base64 encoding, this way no special character can break you application, but you would need to handle it also on the receiving part (decoding).
  • A simplier solutions would be, before hitting the URL, replace all + signs with %2B. This way the other side will be able to decode it normaly, without the need of a special routine.

For more info you should reffer to hthe following stack overflow questions Android: howto parse URL String with spaces to URI object? and URL encoding the space character: + or %20?

2

I am using Angular 7, the + (this one "xyz+manwal") is replaced with a space (like this "xyz manwal") in the URI when it reaches to back-end code.

encodeURI() dindn't work for me, I used encodeURIComponent() it converted + to %2B

     encodeURIComponent("xyz+manwal") => "xyz%2Bmanwal"

below is the example code

    // filter = xyz+manwal
    let filterString =  encodeURIComponent(filter); // filterString = xyz%2Bmanwal

    return this.http.get<ListResults>("http://website/query-results?" + filterString ).pipe(
      retry(3),
      catchError(........)
    )
ddc
  • 885
  • 6
  • 12
1

I have found solution and posting it for future reference. Angular js was converting + sign into %2B.

Following code prevented that:

.config([
    '$provide', function($provide) {
      $provide.decorator('$browser', function($delegate) {
        let superUrl = $delegate.url;
        $delegate.url = (url, replace) => {
          if(url !== undefined) {
            return superUrl(url.replace(/\%2B/g,"+"), replace);
          } else {
            return superUrl().replace(/\+/g,"%2B");
          }
        };
        return $delegate;
      });
    }
  ])
Manwal
  • 23,450
  • 12
  • 63
  • 93
1

Use new HttpUrlEncodingCodec().encodeValue("+91")

Vijay Babu
  • 33
  • 8
0

Below code can help: by adding("-")

queryParams: {
    category: product.category,
    '': product.title.toString().replace(/\s/g, '-')
}
pistou
  • 2,799
  • 5
  • 33
  • 60
Tanmay Ingole
  • 73
  • 2
  • 9
  • 1
    While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 12 '22 at 17:19
0

Use JavaScript function: encodeURIComponent().

In this case, encode string as : encodeURIComponent("xyz+manwal"). output will be xyz%2Bmanwal

NepoKale
  • 55
  • 5
0

We solved this problem by converting the way we marshal the data up to the server. Instead of sending it as querystring parameters on the target URL we are now posting the data in the body of the http request. Data passed on the querystring is exposed to all the risks of the transport; encoding conversion and also the risk of exceeding the legal length of the URL. Sending the data within the body eliminates these issues.

Of course, this isn't relevant if you need the data on the URL. But if you don't need the data on the URL, transporting the data values on the URL as opposed to within the body is like duct-taping yourself to the wing, when you could be riding in coach! :-)

Anyway, this solved our problem. I hope this can help solve yours.

Yossi G.
  • 939
  • 1
  • 8
  • 22
0

Not tested above mentioned answers but you can simply use following easy and tested solution

let username='testuser+3@gmail.com';
let encodedUsername=encodeURIComponent(username);

this will gives you following result

testuser%2B3%40gmail.com
Zeshan
  • 71
  • 6
0

If any of these fails to stop converting '+' to '%2B'

  1. encodeURIComponent, encodeURI - Not working
  2. decodeURIComponent, decodeURI - Not working

Then try this

Split the URL using '+' and pass using fragments like below

if (this.relativeInternalUrl.includes('+')) {
        this.router.navigate([this.relativeInternalUrl?.split('+')[0]], {
          fragment: this.relativeInternalUrl?.split('+')[1],
        });
      } else {
        this.router.navigate([this.relativeInternalUrl]);
      }
Surya R Praveen
  • 3,393
  • 1
  • 24
  • 25