数据来源
主要考虑几种情况:
- 从 Nginx 转发过来. 考虑解析
X-Forwarded-For
或者X-Real-IP
请求头, 具体可以根据实际情况取舍, 也可以两个都解析 (需要nginx做相应的配置) - 直接请求到 Kestrel. 可从
HttpContext.Connection.RemoteIpAddress
字段中读取出来. - 在没有做其他额外配置的情况下, 代理服务器(如nginx, apache)中会记录
REMOTE_ADDR
请求头信息, 表示直接请求到这里的客户端IP, 这中间也可能是某个中转的服务器.
示例代码
注入: IHttpContextAccessor 由 .NetCore 依赖注入
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Octopus.TaskUrl.Api
{
public class RequestIpHelper
{
private readonly IHttpContextAccessor _httpContextAccessor;
public RequestIpHelper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string GetRequestIP()
{
string ip = SplitCsv(GetHeaderValueAs<string>("X-Forwarded-For")).FirstOrDefault();
if(string.IsNullOrWhiteSpace(ip))
ip = SplitCsv(GetHeaderValueAs<string>("X-Real-IP")).FirstOrDefault();
if (string.IsNullOrWhiteSpace(ip) && _httpContextAccessor.HttpContext?.Connection?.RemoteIpAddress != null)
ip = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
if (string.IsNullOrWhiteSpace(ip))
ip = GetHeaderValueAs<string>("REMOTE_ADDR");
if (string.IsNullOrWhiteSpace(ip))
throw new Exception("Unable to determine caller's IP.");
return ip;
}
public T GetHeaderValueAs<T>(string headerName)
{
StringValues values;
if (_httpContextAccessor.HttpContext?.Request?.Headers?.TryGetValue(headerName, out values) ?? false)
{
string rawValues = values.ToString();
if (!string.IsNullOrWhiteSpace(rawValues))
return (T)Convert.ChangeType(values.ToString(), typeof(T));
}
return default;
}
public static List<string> SplitCsv(string csvList)
{
if (string.IsNullOrWhiteSpace(csvList))
return new List<string>();
return csvList
.TrimEnd(',')
.Split(',')
.AsEnumerable<string>()
.Select(s => s.Trim())
.ToList();
}
}
}