如何获取NextJs项目中的页面URL或主机名?

问题描述 投票:0回答:17

我想在静态站点生成器上获取页面的完整 URL 或站点主机名,如下图所示。

我会尝试使用

window.location.hostname
,但它不起作用。

错误:窗口未定义。

reactjs next.js hostname domain-name base-url
17个回答
42
投票

如果您想要服务器端 getInitialProps 中的主机名,您仍然可以从 req 获取它

Home.getInitialProps = async(context) => {
   const { req, query, res, asPath, pathname } = context;
   if (req) {
      let host = req.headers.host // will give you localhost:3000
     }
  }

35
投票

通过服务器端渲染(

getServerSideProps
),您可以使用
context.req.headers.host

import type { GetServerSideProps, NextPage } from "next";

type Props = { host: string | null };

export const getServerSideProps: GetServerSideProps<Props> =
  async context => ({ props: { host: context.req.headers.host || null } });

const Page: NextPage<Props> = ({ host }) => <p>Welcome to {host || "unknown host"}!</p>;

export default Page;

但是使用静态生成(

getStaticProps
),主机名不可用,因为没有请求从中获取它。一般来说,服务器不知道自己的公共主机名,因此您需要告诉它。使用 Next.js 环境变量,将其放入
.env.local
:

HOST=example.com

然后使用

process.env['HOST']
访问它:

import type { GetStaticProps } from "next";

export const getStaticProps: GetStaticProps<Props> = 
  async context => ({ props: { host: process.env['HOST'] || null }});

30
投票

如果您想获得完整的网址:

import { useRouter } from 'next/router';
const { asPath } = useRouter();
    const origin =
        typeof window !== 'undefined' && window.location.origin
            ? window.location.origin
            : '';

    const URL = `${origin}${asPath}`;
    console.log(URL);

16
投票

您访问的位置

window
请确保添加检查,以便代码仅在浏览器上执行,而不会在 SSG 期间执行”

if (typeof window !== 'undefined') {
   const hostname = window.location.hostname;
}

更新: 如果您在

basePath
中指定了
next.config.js
:

module.exports = {
  basePath: 'https://www.example.com/docs',
}

然后使用

useRouter
,您可以访问基本路径:

import { useRouter } from 'next/router'

function Component() {
   const router = useRouter();
   
   console.log({ basePath: router.basePath}); 
   // { basePath: 'https://www.example.com/docs' }

   ...
}

但是如果你有相对基本路径,那么你可以使用第一种方法


11
投票

考虑这个包> next-absolute-url

import absoluteUrl from 'next-absolute-url'
const { origin } = absoluteUrl(req)
const apiURL = `${origin}/api/job.js`

如果您现在部署了 Next.js 应用程序,apiURL 将类似于

https://your-app.now.sh/api/job.js

但是,如果您在本地运行应用程序,则 apiURL 将改为

http://localhost:8000/api/job.js


11
投票

根据此处提到的答案,您可以使用以下代码使用新的应用程序目录(用于服务器端组件)在 Next 13 中获取主机名:

import { headers } from 'next/headers';

export default function Home() {
  const headersList = headers();
  
  headersList.get('host'); // to get domain
  headersList.get('next-url'); // to get url

  return <div>....</div>
}

注意:请注意在布局或页面中使用它会在请求时选择进入动态渲染的路线


8
投票

使用

typeof window !== 'undefined'
是安全的方法。
if (window) {}
会给你带来麻烦。

const hostname = typeof window !== 'undefined' && window.location.hostname ? window.location.hostname : '';
const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';

使用上面的代码将为您提供客户端使用的前端/外部主机名/来源:

example.com
www.example.com
www.example.com:80
等,而不是
localhost
之类的东西。
useRouter()
将返回服务器端主机名/来源(
localhost
localhost:3000


8
投票

我相信你最好结合使用

useRouter
useEffect
钩子来做到这一点。就我而言,我想动态设置网页的
og:url
。这就是我所做的。我们将
router.pathname
作为依赖项,以便每次移动到不同页面时都会更新
ogUrl

import { useRouter } from "next/router";
import { useState, useEffect } from "react";

const MyComponent = () => {

  const router = useRouter();
  const [ogUrl, setOgUrl] = useState("");


  useEffect(() => {
    const host = window.location.host;
    const baseUrl = `https://${host}`;

    setOgUrl(`${baseUrl}${router.pathname}`);
  }, [router.pathname]);


  return <div></div>
}

4
投票

您需要确保对

window.location.hostname
的访问仅发生在客户端,而不是在服务器端渲染期间(其中
window
不存在)。您可以通过将其移动到组件中的
useEffect
回调来实现这一点。

function Component() {
    useEffect(() => {
        console.log(window.location.hostname) 
        console.log(window.location.href) // Logs `http://localhost:3000/blog/incididunt-ut-lobare-et-dolore`
    }, [])
    
    // Remaining code of the component
}

3
投票

这是我解决这个问题的方法,这也适用于 Next.js 13 App Router:

创建一个钩子,将其命名为use-origin.jsx(或.tsx),并将其添加到根目录中的/hooks文件夹中:

'use client'; // this is Next 13 App Router stuff

import { useEffect, useState } from "react";

export default function useOrigin() {
  const [mounted, setMounted] = useState(false);
  const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';

  useEffect(() => {
    setMounted(true)
  }, [])

  if (!mounted) {
    return null
  }

  return origin;
}

现在使用此钩子访问您的动态 BASE_URL 路由:

"use client";

import useOrigin from "@/hooks/use-origin"

export default function Test() {
  const origin = useOrigin();

  return (
    <div>{origin}</div>
  )
}

1
投票

req.headers 是符号而不是对象,因此要获取值,请使用 get 方法

const host = req.headers.get("host"); // stackoverflow.com

1
投票

使用添加到项目根目录的 middleware.js 文件可以让您访问主机名,并在需要时提供很大的灵活性来基于它执行操作。

https://nextjs.org/docs/advanced-features/middleware

// Example: redirecting a domain to a subdomain

import { NextResponse } from "next/server";

// This function can be marked `async` if using `await` inside
export function middleware(request) {
  // Currently there is no main site so we redirect to the subdomain.
  const host = request.headers.get("Host");
  if (
    process.env.NODE_ENV === "production" &&
    host.startsWith("mydomain.com")
  ) {
    return NextResponse.redirect(new URL("https://mysubdomain.mydomain.com"));
  } else if (
    process.env.NODE_ENV === "staging" &&
    host.startsWith("staging.mydomain.com")
  ) {
    return NextResponse.redirect(
      new URL("https://mysubdomain-staging.mydomain.com")
    );
  }
}

0
投票

据我所知有两种方法可以做到这一点:

  1. Next JS 为我们提供了 useRouter 钩子,首先你必须将它导入到你的组件中,然后,要使用 router 对象,你只需要声明它即可。例如:

    const 路由器 = useRouter();

    console.log(路由器.路径名);

    const {路径名} = 路由器; <---- To access the pathname directly.

除此之外,正如@Xairoo之前所说,如果你想使用window对象,你必须检查是否

window !== 'undefined'
以避免错误。发生 window not Define 错误是因为 Next JS 使用 NodeJS 来渲染应用程序,而 Node JS 中未定义 window 对象。

您可以在this链接中找到更详细的解释。


0
投票

没有哦,上面的答案解决了问题,这是我找到的解决方案:

function return_url(context) {
  if (process.env.NODE_ENV === "production") {
    // if you are hosting a http website use http instead of https
    return `https://${context.req.rawHeaders[1]}`;
  } else if (process.env.NODE_ENV !== "production") {
    return "http://localhost:3000";
  }
}

以及您使用的 getServerSideProps 或 getStaticProps 函数

export async function getServerSideProps(context) {
  let url = return_url(context);
  const data = await fetch(`${url}/yourEndPoint`).then((res) => res.json());
  return {
    props: {
      data: data,
    },
  };
}

0
投票

如果有人正在寻找一种在应用程序目录中执行此操作的简单方法。

import { headers } from "next/headers";

export default function Page() {
  const headerList = headers();
  const domain = headerList.get("x-forwarded-host") || headerList.get("host") || "beta.popstarz.ai";
  console.log(domain);

  return (
    <main className="flex min-h-screen flex-col items-center justify-between py-3 pb-safe-bottom">
       ... 
    </main>
  );
}


-2
投票

在 Next.js 中你可以这样做, 在客户端通过useEffect获取window.location.origin, 并将其设置为状态。

工作良好: { “下一个”:“12.1.6”, “反应”:“18.1.0”, }

const Home: NextPage = () => {
  const { asPath, query } = useRouter();

  const [loading, setLoading] = useState(false);
  const [loginCallBackURL, setLoginCallBackURL] = useState("");
 
  useEffect(() => { 
      setLoginCallBackURL(
        `${window.location.origin}/${query.redirect ? query.redirect : "user"}`,
      ); 
  }, []);

  // if you do something like this, it can't get loginCallBackURL
  // const loginCallBackURL = useMemo(() => {
  //   if (typeof window !== 'undefined') {
  //     return `${window.location.origin}/${
  //       query.redirect ? query.redirect : "user"
  //     }`;
  //   }
  //   return asPath;
  // }, [asPath, query]);
 
  return (
    <div>
      <Button
        variant="contained" 
        href={queryString.stringifyUrl({
          url: `${publicRuntimeConfig.API_HOST}/auth/google/login`,
          query: {
            callbackURL: loginCallBackURL,
          },
        })}
      >
        Sign in with google
      </Button>
    </div>
  );
};

export default Home;


-3
投票

我们可以这样获取当前的 url:

import { useRouter } from 'next/router';

const router = useRouter();
const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';

const address_url = origin+router.asPath;    
© www.soinside.com 2019 - 2024. All rights reserved.