0

Before I go on, let me say that I've looked through a number of threads already and can't find an answer that works for me.

Basically, I've built a custom link shortener and I'm using URLSearchParams to pull the URL to be shortened and the custom slug from the URL search query as follows:

var e = window.location.search;
const urlParams = new URLSearchParams(e);
const url = urlParams.get("url");
const slug = urlParams.get("slug");

Where the format for a query is: ?url=https://google.com&slug=customslug

After the parameters are handled, the URL string is treated with trim() to remove any whitespace. The final output is encoded with encodeURIComponent() when the API I'm using (https://short.io) is called.

However, I want to be able to pass URLs with &, like so: ?url=https://google.com/&testing&slug=customslug. My ideal solution would simply treat any & that isn't part of the &slug parameter as a part of the URL contained within the &url parameter. Currently, the & character is ignored if it isn't attached to a valid parameter (url or slug).

I have tried encoding the query input using encodeURIComponent(), but that results in a failure to pick up on either defined parameter. I have also tried splitting the input using split("&slug",1), but that results in an array and I cannot pass arrays to the Short.io API.

Any suggestions?

Owen Sullivan
  • 103
  • 2
  • 9
  • I'm not sure I follow entirely - you need to encode the _individual parts_ (`url`, `slug`) with `encodeURIComponent`, not the whole thing. (Or use `URLSearchParams`/`URL` also for _creating_ the query string, it will handle that for you.) – CherryDT Sep 07 '21 at 18:42
  • @CherryDT I'm lost as to how to encode the individual parts of the string without encoding the entire string. Do you have an example? – Owen Sullivan Sep 07 '21 at 19:23
  • `console.log(\`https://your-service.com/?url=${encodeURIComponent(url)}&slug=${encodeURIComponent(slug)}\`)` - or `const result = new URL('https://your-service.com'); result.searchParams.set('url', url); result.searchParams.set('slug', slug); console.log(result.toString());` - Assuming variables `url` and `slug` with the relevant values here - This is how the correct link to your service should be generated, then you will have no issues getting `url` and `slug` out of the `searchParams` again. – CherryDT Sep 07 '21 at 19:42
  • @CherryDT this is great for assembling the URL, but it doesn't solve the encoding problem. The output is still missing the part of `url` after the ampersand. – Owen Sullivan Sep 07 '21 at 20:09
  • No... if the URL is assembled correctly, it won't miss anything after decoding later. The method I just explained will produce a correctly encoded URL like `https://your-service.com/?url=https%3A%2F%2Fgoogle.com%2F%26testing&slug=customslug`. And `new URL('https://your-service.com/?url=https%3A%2F%2Fgoogle.com%2F%26testing&slug=customslug').searchParams.get('url')` reproduces `https://google.com/&testing` just fine. – CherryDT Sep 07 '21 at 22:52

2 Answers2

1

You should use the URL Encoded ampersand symbol %26.

var e = "?url=https://google.com/%26testing&slug=customslug";
const urlParams = new URLSearchParams(e);
const url = urlParams.get("url");
const slug = urlParams.get("slug");

console.log(url);
console.log(slug);
gunwin
  • 4,578
  • 5
  • 37
  • 59
0

I solved my issue by building off of @CherryDT's comment about using window.location.hash to get my URL string. Ultimately, I chose to forgo the idea of a slug in the address bar, since it would cause further problems with my script.

While this solution is only applicable for my purposes, I'm detailing the solution because it functions as a workaround for the issue of not being able to encode a passed URL string from the address bar. Might be useful to someone, someday.

var e = window.location.href.replace(window.location.hash, '');
if (e.endsWith("?") === true) {
    var url = window.location.hash.substr(1);
    if (url === "") {
        // Error code
    } else {
        console.log("A URL to be shortened was provided via hash.");
        // Pass url to rest of script
     }
 }
Owen Sullivan
  • 103
  • 2
  • 9
  • `?url=https://google.com/&testing&slug=customslug` is a bad query string to begin with, it shouldn't even look like this! As I explained in my comment, the to-be-shortened URL needs to be URL-encoded before it's stuffed into the `url` parameter! For instance, what will happen if the URL has a hash, e.g. `https://pinboard.in/faq/#invisible_account`? It will not only break the hash but also hide the `slug` from you... Or what if the URL has a `slug` too? - You should do it right from the start and not build half-working ways to fix the broken URLs you produce, it's a can of worms otherwise... – CherryDT Sep 07 '21 at 22:57
  • The problem is that `e` in this example is not representative of my actual script. `e` is fed directly from the address bar, not pre-defined. So if my address bar is `https://my-website.com/?url=https://google.com/&testing#testing&slug=customslug`, I can't figure out how to separate the `url` and `slug` to encode `url`. – Owen Sullivan Sep 08 '21 at 18:32
  • But how does this broken URL even get into the address bar in the first place? I think we are going in circles here. You said it's _your_ service, right? So you also built whatever code assembled this incorrect URL that ends up in the address bar, right? My point is that _that's_ the source of the problem that needs to be fixed, not the other side of it. If it was encoded correctly from the start, this problem wouldn't even exist. – CherryDT Sep 09 '21 at 07:32
  • The URL gets into the address bar because I put it there. The point of the feature is that I can simply visit `https://my-website.com?url=[URL]&slug=[slug]` as a shortcut for shortening the URL. The rest of my script includes text boxes where I can input the URL and slug manually, and it encodes them properly. It's the shortcut from the address bar that I can't encode; it looks like I'm going to have to forgo this feature, either that or remove the `slug` functionality from the address bar shortcut so I can simply encode everything after the `url`. – Owen Sullivan Sep 09 '21 at 16:57
  • suggestion: put the slug as optional query string and the URL as hash... `https://example.com/#[URL]` or `https://example.com/?slug=[slug]#[URL]` - since you seem to read the info client-side anyway, the hash can be accessed. then you have no issues at all because you can get the original URL using `window.location.hash.substr(1)`. (You could also take the idea of requiring the URL to be the last argument - _after_ slug - and apply it to query string parameters only, but then you still have issues with a hash and you have to awkwardly split the query string - URL as hash should solve all that) – CherryDT Sep 09 '21 at 19:13
  • Or did you consider using a bookmarklet? You can create a `javascript:` bookmark that takes the current website's URL, asks for an optional slug using `prompt` and then opens a new window with the correctly encoded final URL. Should be even easier to use than manually putting it into the address bar. – CherryDT Sep 09 '21 at 19:17
  • The hash string idea was perfect. I messed around a bit with adding back the `slug` query string after the fact, but I ultimately discovered it was far less messy to just omit it for the purpose of quickly shortening a URL and to simply check for the existence of `?` before the hash to ensure other parts of the page would function if a hash value was provided without the `?` (for example, if I wanted the page to jump to `#section` separately from URL shortening). I updated my answer above. – Owen Sullivan Sep 09 '21 at 21:48