vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.72k stars 26.62k forks source link

URLSearchParams Not Decoded #68133

Closed Carlwirkus closed 1 month ago

Carlwirkus commented 1 month ago

Link to the code that reproduces this issue

https://github.com/Carlwirkus/next-searchparams

To Reproduce

Start a new application Navigate to http://localhost:3000?foo=1%26bar=2

Current vs. Expected behavior

Current

searchParams: { foo: '1&bar=2' } }

Expected

searchParams: { foo: '1', bar: '2' } }

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.5.0: Wed May  1 20:14:38 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6020
  Available memory (MB): 16384
  Available CPU cores: 10
Binaries:
  Node: 20.9.0
  npm: 10.1.0
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.2.5 // Latest available version is detected (14.2.5).
  eslint-config-next: 14.2.5
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.5.4
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Navigation

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

URLs are not decoded before they are parsed by URLSearchParams. This is not the expected behaviour.

AlbersJoy0629 commented 1 month ago

This problem occurs because of the way URL encoding and decoding works. The URL http://localhost:3000?foo=1%26bar=2 encodes the ampersand (&) as %26, so it gets interpreted as part of the value of the foo parameter instead of as a delimiter between query parameters. If you want to get result like searchParams: { foo: '1', bar: '2' } }, please use & instead of %26.

http://localhost:3000?foo=1&bar=2

Carlwirkus commented 1 month ago

Yes, would it not be common sense for these to be decoded?

In my case, our email marketing platform appends UTM parameters with percent encoding. As the router does not decoded the URL, the links are broken.

AlbersJoy0629 commented 1 month ago

Could you provide the code that get data from this URL? I mean the code that decoded http://localhost:3000?foo=1%26bar=2 to searchParams: { foo: '1&bar=2' } }

Carlwirkus commented 1 month ago

Unfortunately, this is just default behaviour. If you JSON.stringify(props) you'll see the searchParams: { foo: '1&bar=2' } }

https://github.com/Carlwirkus/next-searchparams/blob/main/app/page.tsx

AlbersJoy0629 commented 1 month ago

Try to decode the parameters manually.

export default function Home() {
  const [params, setParams] = useState({});
  const router = useRouter();

  useEffect(() => {
    const { query } = router;
    const decodedParams = {};

    for (const key in query) {
      if (query.hasOwnProperty(key)) {
        decodedParams[key] = decodeURIComponent(query[key]);
      }
    }

    setParams(decodedParams);
  }, [router.query]);

  ...
}
Carlwirkus commented 1 month ago

Thanks, I understand there are ways to manually decode searchParams from the URL.

I feel like either: this should be decoded by default or Next should have some way add/change the decoding.

icyJoseph commented 1 month ago

Hi, as per spec & is a special character which is used to separate the query parameters.

Source, The characters ";", "/", "?", ":", "@", "=" and "&" are the characters which may be reserved for special meaning within a scheme

With that being said, we can see how this is implemented into the Web APIs:

// run this in your own browser console
new URL("http://localhost:3000?foo=1%26bar=2").searchParams.get("foo")

We can see that it prints back: '1&bar=2'

That's the value of foo, as you define it, and compliant to spec. What is Next.js supposed to do for you here. If they had some behavior changing the encoding, there'd be people complaining that it doesn't respect the spec.

xpf629629 commented 1 month ago

image

How did you get k: v, i get empty

Carlwirkus commented 1 month ago

Hi, as per spec & is a special character which is used to separate the query parameters.

Source, The characters ";", "/", "?", ":", "@", "=" and "&" are the characters which may be reserved for special meaning within a scheme

With that being said, we can see how this is implemented into the Web APIs:

// run this in your own browser console
new URL("http://localhost:3000?foo=1%26bar=2").searchParams.get("foo")

We can see that it prints back: '1&bar=2'

That's the value of foo, as you define it, and compliant to spec. What is Next.js supposed to do for you here. If they had some behavior changing the encoding, there'd be people complaining that it doesn't respect the spec.

Thanks, so the issue here is that the marketing email provider (Mailchimp) is encoding URLs incorrectly.

I think It'd be nice to have a mechanism to decode the URL before they are passed to the URLSearchParams but maybe that's attacking the problem from the wrong side.

github-actions[bot] commented 3 weeks ago

This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.