Angular url plus sign converting to space

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
    }
]

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);

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.


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');

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?