如何在不重新加载页面的情况下将服务器端重定向到其他页面并仍将 URL 保留在 Nextjs 应用程序中?

Posted

技术标签:

【中文标题】如何在不重新加载页面的情况下将服务器端重定向到其他页面并仍将 URL 保留在 Nextjs 应用程序中?【英文标题】:How to server side redirect to other page without reloading the page and still keeping the url in Nextjs app? 【发布时间】:2021-06-02 23:30:36 【问题描述】:

我有一个[slug].js 页面,它将获取 API 以获取目标页面

export async function getServerSideProps( query, res ) 
    const slug = query.slug;
    try 
        const destination = await RoutingAPI.matchSlug(slug);
        res.writeHead(302,  Location: destination );
        res.end();
        // return 
        //     redirect: 
        //         permanent: true,
        //         destination,
        //     ,
        // 
     catch (error) 
        return 
            notFound: true
        
    

如果我的客户端从另一个页面重定向到 slug 页面,它可以工作并保持 URL 与 slug 相同,但它会使浏览器重新加载。如果我使用

return 
     redirect: 
        permanent: true,
        destination,
     ,

它不会重新加载浏览器,但它会将 URL 更改为目标,与 slug 不同。我该如何解决这个问题?我会很感激任何想法,谢谢

【问题讨论】:

你能建立一个 repo 来重现这个问题吗?如果您还可以提供您获得的 URL 序列与您期望的 URL 序列,那也很好 @diedu 你可以在这里签到codesandbox.io/s/thirsty-sound-5wvy8,我希望目标页面将 url 保留为“something-slug”,而不是“destination” 您如何在客户端进行重定向?你提到的那个有效 我看不到使用当前自定义选项实现此目的的方法,您可以查看自定义服务器或重写功能,但我建议您在 github 上打开讨论以添加 asgetServerSideProps 返回的重定向中的选项。天知道要多久才能上线:/ @iamhuynq 你的目标到底是什么?您想为某些“目的地”显示不同的组件(页面)并使用不同的getServerSideProps,但保留网址? 【参考方案1】:

您可以使用重写来实现这一点。来自docs:

重写允许您将传入请求路径映射到不同的目标路径。

在您的next.config.js 中添加:

module.exports = 
  async rewrites() 
    return [
      
        source: "/:slug",
        destination: "/your-destination",
      ,
    ];
  ,
;

rewrites 是一个异步函数,它期望返回一个数组,其中包含具有源和目标属性的对象:

source 是传入的请求路径模式。 destination 是您要路由到的路径。

【讨论】:

我认为这不是 OP 想要的。似乎他需要根据一些运行时数据重写请求,他将 slug 传递给一些 api 并获得最终目的地作为回报,然后重写发生。所以你事先并不知道目的地。【参考方案2】:

好的,我有一个解决方案,它不会重新加载,也不会更改 url.. 但是它需要一些客户端脚本.. 如下例所示

希望你能找到你喜欢的 :D

这是我的codesandbox

index.js(来自您的代码框)

import Link from "next/link";

export default function IndexPage() 
  return (
    <div>
      Hello World." "
      <Link href="/something-slug">
        <a id="myElem">Go to slug pageee</a>
      </Link>
      <script
        dangerouslySetInnerhtml=
          __html: `
          let elem=document.getElementById('myElem')
          elem.addEventListener('click',async function(event)
            event.preventDefault()
            console.log(event.path[0].href)
            let myFetch=await fetch(event.path[0].href)
            let text=await myFetch.text()
            let newHTML=document.createElement('html')
            newHTML.innerHTML=text
            let _next=document.getElementById('__next')
            _next.innerHTML=""
            let requestedNext=[...newHTML.getElementsByTagName('div')].filter(a=>a.id=="__next")[0]
            let scripts=[...requestedNext.getElementsByTagName('script')]
            scripts.forEach(a=>eval(a.innerHTML)) //eval any scripts sent by YOUR requested _next
            console.log(requestedNext)
            _next.innerHTML=requestedNext.innerHTML
          )
          `
        
      ></script>
    </div>
  );

slug.js(同样,来自您的代码框)

export default function AboutPage() 
  return <div>About us</div>;


export async function getServerSideProps( query, req, res ) 
  return ;

【讨论】:

什么?怎么样?对我来说很好用..对提问者来说很好用..你能详细说明吗? @Danila 也.. 在你说它会破坏之前仔细查看__html.. 它只会加载你返回到客户端的内容(而不是加载到的其他反应内容的整个列表您没有与之打交道的客户端) 首先,这与 OP 问题无关,即使他以某种方式批准赏金问题是关于不同主题的。其次,你所做的实际上也破坏了很多 React 代码和 Next 数据获取,基本上你所有的 hack 都可以替换为 Link as 属性。使用服务器端数据获取的实际工作示例:codesandbox.io/s/https***comquestions66472986-02qpz 所以你的问题是没有得到赏金?我刚刚编辑了我的问题,所以你不能说“我保留减号,因为我不能删除它”。这是一个很好的答案,为什么你不在我面前发布你的答案?我的意思是您可以编辑该代码框以转到“/something-slug”,并且您有一个有效的答案 我没有发布答案,因为我不知道 OP 问题的答案。他需要从getServerSideProps 内部重定向,而不是从链接点击。

以上是关于如何在不重新加载页面的情况下将服务器端重定向到其他页面并仍将 URL 保留在 Nextjs 应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不重新加载页面的情况下将任意 JSON 发送到 node.js?

路由更改时如何在不滚动 Reactjs 的情况下将页面置于顶部

如何在不重新初始化当前帧内容的情况下将一帧的内容加载到另一帧

如何在不重新加载网格的情况下将行添加到下一页中的 jqGrid?

在不使用 jQuery 重新加载页面的情况下将 Flask 输入更新为 HTML [重复]

如何在不重新加载 HTML 页面的情况下重定向锚标记链接?