Swift URL appendingPathComponent converts `?` to `%3F`
Asked Answered
P

7

17
let url = URL(string: "https://example.com")
let path = "/somePath?"
let urlWithPath = url?.appendingPathComponent(path)

After appending, the path /somePath? becomes somePath%3F.

The ? becomes a %3F. Question Mark is replaced with the percent-encoded escape characters.

The URL does output correctly if I use:

let urlFormString = URL(string:"https://example.com/somePath?")

Why does appendingPathComponent convert ? to %3F?

How can I use appendingPathComponent if the path component contains a question mark?

Peruzzi answered 28/12, 2018 at 7:34 Comment(1)
When you call appendingPathComponent, you shouldn’t include either the leading / nor the trailing ?. If you want to add query to URL, you should consider using URLComponents.Unconcerned
O
14

The generic format of URL is the following:

scheme:[//[userinfo@]host[:port]]path[?query][#fragment]

The thing you have to realize is that the ? is not part of the path. It is a separator between path and query.

If you try to add ? to path, it must be URL-encoded because ? is not a valid character for a path component.

The best solution would be to drop ? from path. It has no meaning there. However, if you have a partial URL which you want to append to a base URL, then you should join them as strings:

let url = URL(string: "https://example.com")
let path = "/somePath?"
let urlWithPath = url.flatMap { URL(string: $0.absoluteString + path) }

In short, appendingPathComponent is not a function that should be used to append URL query.

Ofilia answered 28/12, 2018 at 9:3 Comment(0)
N
9

You should use removingPercentEncoding on URL's absoluteString,

let url = URL(string: "https://example.com")
let path = "/somePath?"
let urlWithPath = url?.appendingPathComponent(path).absoluteString.removingPercentEncoding
print(urlWithPath!)
Nerte answered 28/12, 2018 at 8:54 Comment(2)
Unless URL contains other characters that should be URL encoded, because then this "solution" would break.Ofilia
I was looking for this! You saved my day :DIdeally
S
0

%3F stands for ?, according to URL Encoding. So if you create an URL - it has to be that way. If, for some reason, you need your ?, create a string, not URL.

Check urlWithPath.lastPathComponent to see that everything is all right (prints: "somePath?")

Songster answered 28/12, 2018 at 7:41 Comment(0)
A
0

When you convert the string to URL, It'll be doing PercentEncoding in URL. So that your ? has been encoded into %3F.

If you want the url as string with ?, you can remove the PercentEncoding as like below code.

let urlString = urlWithPath?.absoluteString.removingPercentEncoding

Output: https://example.com/somePath?

Aubine answered 28/12, 2018 at 7:50 Comment(0)
D
0

First of all it is not a problem. this is a mechanism called URL encoding, for translating unprintable or special characters to a universally accepted format by web servers and browsers.

For more information you can go to https://www.techopedia.com/definition/10346/url-encoding

URL encoded chars, https://www.degraeve.com/reference/urlencoding.php

Dekko answered 28/12, 2018 at 8:0 Comment(0)
B
0

Instead of URL can use URLComponents:

var url = URLComponents()

Set the scheme, host and path:

url.scheme = "https"
url.host = "example.com"
url.path = "/somePath"

Set the query as empty string and ? is added since it is a separator between path and query:

url.query = ""
// url.queryItems = [URLQueryItem(name: "nameN", value: "valueX")]

Prints: https://example.com/somePath?

print(url)
Balch answered 18/9, 2022 at 18:21 Comment(0)
N
-1

You can build your url using NSString class:

let urlStr = "https://example.com" as NSString
let path = "/somePath?"
let urlStrWithPath = urlStr.appendingPathComponent(path)
let url = URL(string: urlStrWithPath)

This way, special characters are not url-encoded in the final url.

Newcomen answered 14/6, 2019 at 10:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.