Next.js: Link with absolute url throws errors

Created on 29 Aug 2019  路  4Comments  路  Source: vercel/next.js

Bug report

The <Link> component no longer works with absolute urls, even when these urls don't navigate to a different domain.

Describe the bug

While updating NextJS from 9.0.1 to 9.0.5 I noticed that the Router complains when href contains a protocol ( from an absolute url ), even when this url does not navigate away from the SPA.

To Reproduce

Create a <Link href="http://localhost:3000/a" /> and see Router.prefetch. This is the PR that introduced the behavior ( https://github.com/zeit/next.js/pull/8231 0.

https://github.com/ReinoutStevens/nextjs-link-absolute-url

Expected behavior

Absolute urls that do not leave the application should work. Ideally, <Link> supports href's going to external domains as well ( see additional context ).

System information

  • Version of Next.js: [e.g. 9.0.5, latest]

Additional context

Apparently <Link> should not be used to link to external domains, even though this was supported. Is there a motivation for this, as we have content that can only be served over http, and other content that is served over https. We cannot know this beforehand, and it would be nice if we can just consistently use <Link> throughout the app, where a link to an external site would just place the href on the <a> element. Could I also get a clarification on NextJS stand on this behavior, and whether we should build our own Link component that supports this behavior.

Most helpful comment

We host and share content ( think youtube, where the video container itself is an iframe that people can embed, and the rest of the page are related videos, social features etc ). The video container would be on example.com/videocontainer/my-cool-video, and the whole page would be example.com/video/my-cool-video. Some of this content is only accessible on http. You cannot put an iframe to http content on an https site, as your browser will refuse to fetch insecure content.

In general we prefer to be on https, and so we have https://example.com/video/https-content, but for the case of http content we must go to http://example.com/video/http-content.

For this issue specific: when you do <Link href="https://example.com/video/my-video" /> while already being on https://example.com the Router.prefetch should not throw an error, as the absolute URL can be prefetched.

And in general: the <Link> component checks whether a url isLocal or not ( ie, a relative url is local, and an absolute url is local when it has the same protocol and host ). Regardless of this test, it tries to prefetch the page, which throws an error in both cases where the link would be pre-fetchable, and also when the link goes to an external site ( or in our case, when you switch from http to https and vice versa ).

We can create our own <Link> component that does the check, and renders either a nextjs/link or just places the href on the a element, but I see no reason why this behavior couldnt or wouldnt be handled by NextJS ( as it used to be ).

All 4 comments

I feel something isn't right about this issue.

we have content that can only be served over http, and other content that is served over https

Isn't the next app itself should be served from same server? I primary use to route between next's pages internally, not for fetching external resources. The other content you mentioned, is it image, video, or data api? If so, I see no reason to use to route the page into those resources.

We host and share content ( think youtube, where the video container itself is an iframe that people can embed, and the rest of the page are related videos, social features etc ). The video container would be on example.com/videocontainer/my-cool-video, and the whole page would be example.com/video/my-cool-video. Some of this content is only accessible on http. You cannot put an iframe to http content on an https site, as your browser will refuse to fetch insecure content.

In general we prefer to be on https, and so we have https://example.com/video/https-content, but for the case of http content we must go to http://example.com/video/http-content.

For this issue specific: when you do <Link href="https://example.com/video/my-video" /> while already being on https://example.com the Router.prefetch should not throw an error, as the absolute URL can be prefetched.

And in general: the <Link> component checks whether a url isLocal or not ( ie, a relative url is local, and an absolute url is local when it has the same protocol and host ). Regardless of this test, it tries to prefetch the page, which throws an error in both cases where the link would be pre-fetchable, and also when the link goes to an external site ( or in our case, when you switch from http to https and vice versa ).

We can create our own <Link> component that does the check, and renders either a nextjs/link or just places the href on the a element, but I see no reason why this behavior couldnt or wouldnt be handled by NextJS ( as it used to be ).

It would load /_next/static/<buildid>/pages/https://example.org/.js first and then refresh the page.

You can write a wrapper for <Link> if you really want it but it's better to just use <a> for the case that you're describing.

Eventually <Link> will go away and we'll just support <a> to link around.

I also had the same issue when pass absolute url to Link.
Try to set prefetch as false.
<Link href="YOUR_LINK" prefetch={false} />
It worked for me.
Cheers!

Was this page helpful?
0 / 5 - 0 ratings