如何在Next.js应用程序的服务器端获取客户端的IP地址?

18

我想获取用户的时区和位置信息,以根据其位置和时区呈现服务器端页面,但是我无法从请求中获取用户的IP地址或获取本地主机的IP地址(127.0.0.1)。那么我应该怎么办?

6个回答

22

你可以使用类似request-ip的包。然后在你的API路由中:

import requestIp from 'request-ip'

export default async function myRoute(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const detectedIp = requestIp.getClientIp(req)
}

这个程序包给我错误的IP地址,因为该IP地址的位置是错误的。 - mohamed
你说的IP地址错误是什么意思?它会报告从头部提取的IP地址,甚至会查找“x-forwarded-for”代理头。 - Ivan V.
它给我一个不同于我的IP地址的IP地址,是否有任何配置应该放在nginx上以传递这些头? - mohamed
现在使用这个解决方案可以工作了,但是需要在nginx.config中添加一些配置来传递请求头。 - mohamed
这个程序正在给我提供Azure的页面主机IP地址... @mohamed,你能告诉我你添加了哪些配置吗? - letie

21

使用Next.js应用程序可以检测用户IP地址:

export async function getServerSideProps({ req }) {
  const forwarded = req.headers["x-forwarded-for"]
  const ip = forwarded ? forwarded.split(/, /)[0] : req.connection.remoteAddress
  return {
    props: {
      ip,
    },
  }
}

2
这是对我有效的那个! - letie
1
这种方法可能存在安全风险;X-Forwarded-For 可以被伪造,只有当它来自可信代理时才应该被接受。 - undefined
请注意,req.connection已在Next.js 13中被弃用,请改用req.socket.remoteAddress。 - undefined

5
你可以使用NextRequest对象直接替换原生的Request接口,从而更好地控制你对请求的操作。 参考文献:https://nextjs.org/docs/api-reference/next/server#nextrequest NextRequest具有完整的类型,并且可以从next/server中导入。
import type { NextRequest } from 'next/server'

NextRequest对象是原生请求接口的扩展,具有以下添加的方法和属性:

  1. cookies - 包含来自请求的cookie
  2. nextUrl - 包括一个扩展的、解析过的URL对象,可让您访问Next.js特定的属性,如pathname、basePath、trailingSlash和i18n
  3. geo - 包含请求的地理位置信息
  4. geo.country - 国家代码
  5. geo.region - 地区代码
  6. geo.city - 城市
  7. geo.latitude - 纬度
  8. geo.longitude - 经度
  9. ip - 包含请求的IP地址
  10. ua - 包含用户代理信息

1
请注意,next/server 仅适用于 Next.js 12+ https://blog.logrocket.com/whats-new-next-js-12/ - James Murty
我该怎么使用它?我很难实现它。 - Matheus Ribeiro
4
@MatheusRibeiro 还要注意,NextRequest 仅在 Edge Runtime 上可用。它无法在常规 API 路由或 Node.js 服务器端代码上工作。 - juliomalves

5
您也可以尝试使用页面的getInitialProps
IndexPage.getInitialProps = async ({ req }) => {
  const ip = req.headers["x-real-ip"] || req.connection.remoteAddress;
  return { ip };
};

CodeSandbox示例


它也给了我(127.0.0.1)。在Nginx中是否有任何配置应该使用来传递请求头? - mohamed
在Google Cloud Run中,这不会提供正确的IP地址。它会提供内部负载均衡器的IP地址。 - Jebin
这个解决方案给我私有IP地址,而不是公网IP地址 :( - letie

1
创建一个API页面/路由:/api/get-ip-address, 在/pages/api文件夹下,创建get-ip-address.ts文件并添加以下内容。
import { NextApiRequest, NextApiResponse } from "next";

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  let ipAddress = req.headers["x-real-ip"] as string;

  const forwardedFor = req.headers["x-forwarded-for"] as string;
  if (!ipAddress && forwardedFor) {
    ipAddress = forwardedFor?.split(",").at(0) ?? "Unknown";
  }

  res.status(200).json(ipAddress);
};

export default handler;

在你的页面文件中,使用Axios或Fetch API在useEffect钩子内部获取上述端点(/api/get-ip-address)的数据(使用GET方法)。

0
通常情况下,当用户在NextJS中发送请求时,请求包含一个套接字实例,该实例具有属性,例如远程IP地址、远程端口和其他有用的信息。
因此,对于任何想要准确获取连接远程端IP地址的人,可以像这样操作。
Login.getInitialProps = async ({ req, res }: any) => {
  const ip = req.connection.remoteAddress
  // and use some other api to get location like country from the ip address
  return { ip }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接