.NET Core 5.0 API中间件如何获取请求方服务器IP及主机名
问题场景
- 前端基于Angular 8开发,部署在IP为
123.234.456.XYZ的服务器上 - 后端为.NET Core API,部署在IP为
123.234.456.PQR的独立服务器,前端应用会调用该API接口 - 现有自定义中间件通过如下代码记录客户端IP:
IPAddress remoteIP = context.Connection.RemoteIpAddress;
- 需求为在中间件中获取前端应用所在服务器的IP(即
123.234.456.XYZ),尝试两种方案均未成功:- 读取
IServerVariablesFeature的REMOTE_HOST字段,仅返回API自身主机名,无法获取目标IP,实现代码如下:
IServerVariablesFeature serverVariablesFeature = context.Features.Get<IServerVariablesFeature>(); var hosteName = serverVariablesFeature["REMOTE_HOST"]; Log.Debug($"Request from REMOTE_HOST: {hosteName}");- 通过
Dns.GetHostEntry解析remoteIP对应主机名,返回No such host is known报错,实现代码如下:
string HostName= Dns.GetHostEntry(remoteIP).HostName; Log.Debug($"Request from HostName: {HostName}"); - 读取
问题根因
两个方案失效的核心逻辑错误:Angular默认是客户端渲染框架,生产环境构建后是纯静态资源,运行环境是终端用户的本地浏览器,API请求是用户浏览器直接发往后端的,根本不是前端静态文件所在的123.234.456.XYZ服务器发起的。
context.Connection.RemoteIpAddress拿到的永远是当前发起请求的终端用户公网IP,和前端部署服务器没有任何关联。IServerVariablesFeature的REMOTE_HOST字段仅在IIS托管、且开启反向DNS解析时才会返回请求源的主机名,默认配置下返回的是API服务器自身信息,完全不符合需求。Dns.GetHostEntry报No such host is known是因为绝大多数普通用户的公网IP没有配置反向PTR解析记录,本来就查不到对应主机名。
正确实现方案
根据你的实际业务场景选择对应方案:
方案1:需求为校验请求来源合法性(防止接口被第三方跨域盗用)
不要尝试获取前端服务器IP,请求本身和该服务器无网络层面关联,正确实现方式:
- 给API配置严格的CORS策略,仅允许你的前端访问源,不要使用通配符:
// Program.cs/Startup.cs中注册CORS策略 builder.Services.AddCors(options => { options.AddPolicy("AllowSpecifiedFrontend", policy => { policy.WithOrigins("https://你的前端正式访问域名") .AllowAnyHeader() .AllowAnyMethod(); }); }); // 中间件管道最前端启用CORS app.UseCors("AllowSpecifiedFrontend");
- 额外校验场景下,可以直接读取请求头的
Origin或Referer字段判断来源:
// 自定义中间件中校验来源 if (!context.Request.Headers.TryGetValue("Origin", out var origin) || origin != "https://你的前端正式访问域名") { context.Response.StatusCode = 403; await context.Response.WriteAsync("Invalid request source"); return; }
注意:不要用IP做来源校验,前端如果接入CDN、反向代理IP会动态变化,用域名校验稳定性更高
方案2:需求为日志中记录前端部署服务器IP
该IP和HTTP请求链路无关联,需要前端构建时主动传递:
- Angular环境配置文件
environment.prod.ts中写入前端服务器IP常量:
export const environment = { production: true, frontendServerIp: '123.234.456.XYZ', apiBaseUrl: 'https://123.234.456.PQR' };
- 编写全局HTTP拦截器,所有发往后端的请求自动携带自定义头
X-Frontend-Server-Ip:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http'; import { environment } from 'src/environments/environment'; @Injectable() export class AddFrontendIpInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler) { const modifiedReq = req.clone({ setHeaders: { 'X-Frontend-Server-Ip': environment.frontendServerIp } }); return next.handle(modifiedReq); } }
- 后端中间件直接读取该自定义头记录日志即可:
if (context.Request.Headers.TryGetValue("X-Frontend-Server-Ip", out var frontendIp)) { Log.Debug($"Request static resource server IP: {frontendIp}"); }
注意:自定义请求头可以被随意伪造,仅能用于日志记录,不能作为安全校验依据
方案3:使用Angular SSR(服务端渲染)场景
只有开启Angular SSR时,页面渲染和API请求才是在前端部署服务器123.234.456.XYZ上发起的,此时:
- 如果API服务直接暴露在公网,
context.Connection.RemoteIpAddress可以直接拿到前端服务器IP - 如果API前端有Nginx、CDN等反向代理,需要先配置转发头中间件,放在所有其他中间件最前面:
app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto });
配置完成后再读取context.Connection.RemoteIpAddress即可拿到真实的请求源IP(即SSR前端所在的服务器IP)。
内容的提问来源于stack exchange,提问作者Mannan Bahelim
相关产品推荐
相关产品推荐

