We investigated whether spaces were replaced with a plus sign or % 20 in percent-encoding in some languages.
When seeking the query string of a URL or the body of ʻapplication / x-www-form-urlencoded`, the HTML5 and URL Standard specifications require spaces to be converted to a plus sign (+).
On the other hand, the HTTP server treats both + and % 20 as spaces because there was no clear specification for percent-encoding. Server-side languages do not provide encoding methods or options for ʻapplication / x-www-form-urlencoded` and may substitute encoding methods according to the RFC 3986 specification.
In most cases, you don't need to know if you're replacing spaces with (+) or percent-encoding (% 20), but with OAuth it's a problem.
For OAuth 1.0, percent encoding (RFC 3986) is required for spaces, which results in an error for libraries that employ the plus sign encoding method. Twitter has published a commentary article about percent-encoding.
JavaScript
ʻURLSearchParams` is based on URL Standard. Spaces are replaced with a plus sign.
const params = new URLSearchParams();
params.append("msg", "hello world");
console.log("msg=hello+world" === params.toString());
ʻURLSearchParams also treats% 20` as a space. The results of the analysis are as follows.
const params2 = new URLSearchParams("msg=hello+world");
console.log("hello world" === params2.get("msg"));
const params3 = new URLSearchParams("msg=hello%20world");
console.log("hello world" === params3.get("msg"));
For ʻencodeURIComponent, replace the space with% 20`.
console.log("hello%20world" === encodeURIComponent("hello world"));
If you want to replace the space with a plus sign, add a call to replace.
const ret = encodeURIComponent("hello world").replace(/%20/g, '+')
console.log("hello+world" === ret);
decodeURIComponent replaces% 20 with a space, but not the plus sign.
console.log("hello world" === decodeURIComponent("hello%20world"));
console.log("hello+world" === decodeURIComponent("hello+world"));
Node.js
It's better to prefer ʻURLSearchParams`, which is supported from Node.js v7.0. Shows the previous method before v7.0.
The standard querystring.stringify module replaces spaces with% 20.
const querystring = require('querystring');
const ret = querystring.stringify({ msg: "hello world" });
console.log("msg=hello%20world" === ret);
querystring.parse replaces both+and% 20 with spaces.
const querystring = require("querystring");
console.log("hello world" === querystring.parse("msg=hello+world")["msg"]);
console.log("hello world" === querystring.parse("msg=hello%20world")["msg"]);
If you need an encoding that conforms to the RFC 3986 specification, introduce ljharb / qs.
const qs = require("qs");
console.log("msg=hello%20world" === qs.stringify({ msg: "hello world" }));
console.log("hello world" === qs.parse("msg=hello+world")["msg"]);
console.log("hello world" === qs.parse("msg=hello%20world")["msg"]);
Python 3
Use ʻurllib. ʻUrlencode defaults to a space +
Replace with.
>>> from urllib.parse import urlencode
>>> urlencode({"msg": "hello world"})
'msg=hello+world'
If you specify quote_via = quote, the space will be replaced with% 20.
>>> from urllib.parse import urlencode, quote
>>> urlencode({"msg": "hello world"}, quote_via=quote)
'msg=hello%20world'
Both parse_qs and parse_qsl replace + and % 20 with spaces.
>>> from urllib.parse import parse_qs
>>> parse_qs("msg=hello+world")
{'msg': ['hello world']}
>>> parse_qs("msg=hello%20world")
{'msg': ['hello world']}
Go
Use the net / url module. ʻEncode of type ʻurl.Values replaces spaces with+. ParseQuery replaces+and% 20 with spaces.
package main
import (
"fmt"
"net/url"
)
func main() {
v := url.Values{}
v.Set("msg", "hello world")
fmt.Println(v.Encode())
// msg=hello+world
m, _ := url.ParseQuery("msg=hello+world")
fmt.Println(m["msg"][0])
// hello world
m2, _ := url.ParseQuery("msg=hello%20world")
fmt.Println(m2["msg"][0])
}
QueryEscape converts spaces to+, while PathEscape converts them to % 20. In addition, PathUnescape does not convert+to spaces.
func main() {
fmt.Println("QueryEscape")
fmt.Println(url.QueryEscape("hello world"))
// hello+world
fmt.Println(url.QueryUnescape("hello+world"))
// hello world
fmt.Println(url.QueryUnescape("hello%20world"))
// hello world
fmt.Println()
fmt.Println("PathEscape")
fmt.Println(url.PathEscape("hello world"))
// hello%20world
fmt.Println(url.PathUnescape("hello+world"))
// hello+world
fmt.Println(url.PathUnescape("hello%20world"))
// hello world
}