Explorar o código

新增 IP 工具函数,支持多种方式获取客户端 IP。

wuyi hai 3 meses
pai
achega
dadb95552a
Modificáronse 3 ficheiros con 62 adicións e 2 borrados
  1. 1 0
      src/app.ts
  2. 8 2
      src/controllers/fish.controller.ts
  3. 53 0
      src/utils/ip.util.ts

+ 1 - 0
src/app.ts

@@ -24,6 +24,7 @@ const options: FastifyEnvOptions = {
 export const createApp = async () => {
   const app = fastify({
     disableRequestLogging: true,
+    trustProxy: true, // 信任代理,用于获取真实客户端 IP
     logger: {
       level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
       transport: {

+ 8 - 2
src/controllers/fish.controller.ts

@@ -3,6 +3,7 @@ import { FishService } from '../services/fish.service'
 import { ResultEnum } from '../entities/fish.entity'
 import { UserRole } from '../entities/user.entity'
 import { ListFishQuery, CreateFishBody, UpdateFishBody, DeleteFishBody, StatisticsQuery } from '../dto/fish.dto'
+import { getClientIP } from '../utils/ip.util'
 
 export class FishController {
   private fishService: FishService
@@ -16,9 +17,14 @@ export class FishController {
       const fishData = request.body
 
       if (!fishData.ip) {
-        fishData.ip = request.ip || 'unknown'
+        fishData.ip = getClientIP(request)
       }
-      console.log('ip: ', request.ip)
+      
+      // 调试信息:显示各种 IP 相关信息
+      console.log('request.ip: ', request.ip)
+      console.log('x-forwarded-for: ', request.headers['x-forwarded-for'])
+      console.log('x-real-ip: ', request.headers['x-real-ip'])
+      console.log('最终使用的 IP: ', fishData.ip)
 
       // 检查是否已存在相同 ID 的记录
       let existingFish: any = null

+ 53 - 0
src/utils/ip.util.ts

@@ -0,0 +1,53 @@
+import { FastifyRequest } from 'fastify'
+
+export function getClientIP(request: FastifyRequest): string {
+  const xForwardedFor = request.headers['x-forwarded-for']
+  if (xForwardedFor) {
+    const ips = Array.isArray(xForwardedFor) ? xForwardedFor[0] : xForwardedFor
+    const firstIP = ips.split(',')[0].trim()
+    if (firstIP && firstIP !== '127.0.0.1' && firstIP !== '::1') {
+      return firstIP
+    }
+  }
+
+  const xRealIP = request.headers['x-real-ip']
+  if (xRealIP) {
+    const realIP = Array.isArray(xRealIP) ? xRealIP[0] : xRealIP
+    if (realIP && realIP !== '127.0.0.1' && realIP !== '::1') {
+      return realIP
+    }
+  }
+
+  if (request.ip && request.ip !== '127.0.0.1' && request.ip !== '::1') {
+    return request.ip
+  }
+
+  const cfConnectingIP = request.headers['cf-connecting-ip'] // Cloudflare
+  if (cfConnectingIP) {
+    const cfIP = Array.isArray(cfConnectingIP) ? cfConnectingIP[0] : cfConnectingIP
+    if (cfIP && cfIP !== '127.0.0.1' && cfIP !== '::1') {
+      return cfIP
+    }
+  }
+
+  const xClientIP = request.headers['x-client-ip']
+  if (xClientIP) {
+    const clientIP = Array.isArray(xClientIP) ? xClientIP[0] : xClientIP
+    if (clientIP && clientIP !== '127.0.0.1' && clientIP !== '::1') {
+      return clientIP
+    }
+  }
+
+  return 'unknown'
+}
+
+export function isValidIP(ip: string): boolean {
+  if (!ip || ip === 'unknown' || ip === '127.0.0.1' || ip === '::1') {
+    return false
+  }
+
+  const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
+  const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
+
+  return ipv4Regex.test(ip) || ipv6Regex.test(ip)
+}