Never send un URI encoded parameters to your server from JavaScript

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the javascript category.

Last Updated: 2024-04-18

I was working on some legacy front-end code that redirected the user to a page that consumed GET params:

window.location.href = "/create_user?email=tom+newsletters@example.com"

I found, however, that the email parameter, in the eyes of my backend web server, was missing the plus - substituting a space instead and leading to invalid data:

{email: "tom newsletters@example.com" }
# Instead of {email: "tom+newsletters@example.com" }

The issue is that the plus symbol is the encoding for space inside a URL. I tried encodingURI(url) but that does not operate on pluses... I then tried encodeURIComponent on the whole URL, but that produced gobbledygook.

The only way to get it working was to individually encode the value of each GET parameter with encodeURIComponent:

window.location.href = "/create_user?email="+ encodeURIComponent("tom+newsletters@example.com")

You could, of course, do this at scale with a function. See this Stack Overflow answer.

const encodeGetParams = p => 
  Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&");

const params = {
  user: "María Rodríguez",
  awesome: true,
  awesomeness: 64,
  "ZOMG+&=*(": "*^%*GMOZ"
};

console.log("https://example.com/endpoint?" + encodeGetParams(params))

Lessons

Never send parameters to a server from JavaScript without first encoding them for a URI.

encodingURI does not encode characters that have special meaning within a URI - you must call encodeURIComponent on the individual elements.

Resources