无法分配请求的地址(Cannot assign requested address)的解决方案

搜索错误关键字“Cannot assign requested address”,"返回" JSON 内容,返回的引号是因为其实并不是远程接口返回的,而是 IdentityModel 返回的,毕竟直译后从字面意思理解“无法分配请求的地址”,也可以理解为不能正确发起请求,所以就是在发起请求的过程中产生的错误。

在和运维一起排查后得知被调用服务出现很多 close wait,导致连接数不能及时释放,连接数耗尽,所以就不能再建立新请求了。知道了原因接下来就好办了。顺藤摸瓜,找到发起请求的地方,将能 Close Dispose 的都处理了。

错误返回的完整内容如下:

{
	"AccessToken": null,
	"IdentityToken": null,
	"TokenType": null,
	"RefreshToken": null,
	"ErrorDescription": null,
	"ExpiresIn": 0,
	"Raw": null,
	"Json": null,
	"Exception": {
		"Message": "Cannot assign requested address",
		"Data": {},
		"InnerException": {
			"ClassName": "System.Net.Sockets.SocketException",
			"Message": "Cannot assign requested address",
			"Data": null,
			"InnerException": null,
			"HelpURL": null,
			"StackTraceString": "at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)",
			"RemoteStackTraceString": null,
			"RemoteStackIndex": 0,
			"ExceptionMethod": null,
			"HResult": -2147467259,
			"Source": "System.Private.CoreLib",
			"WatsonBuckets": null,
			"NativeErrorCode": 99
		},
		"StackTrace": "at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)\n   at System.Threading.Tasks.ValueTask`1.get_Result()\n   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)\n   at System.Threading.Tasks.ValueTask`1.get_Result()\n   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)\n   at System.Threading.Tasks.ValueTask`1.get_Result()\n   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)\n   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\n   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)\n   at IdentityModel.Client.TokenClient.RequestAsync(IDictionary`2 form, CancellationToken cancellationToken)",
		"HelpLink": null,
		"Source": "System.Net.Http",
		"HResult": -2147467259
	},
	"IsError": true,
	"ErrorType": 3,
	"HttpStatusCode": 0,
	"HttpErrorReason": null,
	"Error": "Cannot assign requested address"
}

修改前源代码

/// <summary>
/// 统一获取 SpiderBIM token的通用方法
/// </summary>
/// <param name="config">配置信息</param>
/// <returns></returns>
public static TokenResponse GetAuthorizeAsync(SpiderBIMConfigOptions config)
{
    var tokenClient = new TokenClient(config.TokenUrl, config.ClientId, config.ClientSecret);
    var tokenResponse = tokenClient.RequestResourceOwnerPasswordAsync(config.Username, config.Password, config.Scope).GetAwaiter().GetResult();
    if (tokenResponse.IsError)
    {
        Console.WriteLine($"DEBUG {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff} - ---------------------------- 获取 SPDToken 失败 ----------------------------{tokenResponse.ToJsonString()}");
        return null;
    }
    return tokenResponse;
}

修改后的代码

/// <summary>
/// 统一获取 SpiderBIM token的通用方法
/// </summary>
/// <param name="config">配置信息</param>
/// <returns></returns>
public static TokenResponse GetAuthorizeAsync(SpiderBIMConfigOptions config)
{
    using (var tokenClient = new TokenClient(config.TokenUrl, config.ClientId, config.ClientSecret))
    {
        var tokenResponse = tokenClient.RequestResourceOwnerPasswordAsync(config.Username, config.Password, config.Scope).GetAwaiter().GetResult();
        if (tokenResponse.IsError)
        {
            Console.WriteLine($"DEBUG {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff} - ---------------------------- 获取 SPDToken 失败 ----------------------------{tokenResponse.ToJsonString()}");
            return null;
        }
        return tokenResponse;
    }
}

修改后的代码加上了 using 是的 tokenClient 在使用后及时被释放,避免被调用服务出现太多的 close wait。从而导致连接数被占用完。

所以就是因为没有注意到 tokenClient 是可以被 Dispose 的类,并且因为业务关系发起了频繁的请求,所以才导致问题的产生。

### Java HTTP 请求 "Cannot assign requested address" 错误解决方案 当遇到 `Cannot assign requested address` 的错误时,通常意味着尝试使用的本地地址不可用或未正确配置。对于Java应用程序来说,这可能是由于试图绑定到一个不存在的网络接口或已被占用的端口。 #### 1. 检查本地主机上的可用网络接口 确保正在尝试连接的IP地址确实存在于当前机器上,并且不是被禁用的状态。可以通过执行命令来获取所有活动网络适配器的信息: ```bash ifconfig -a ``` 或者,在Windows环境中使用: ```cmd ipconfig /all ``` 如果目标是特定的IP地址,确认这个地址属于某个已启用并正常工作的网卡[^2]。 #### 2. 修改JVM参数指定源地址 有时,默认情况下JVM会选择不适合的网络接口作为发出请求的源头。为了强制它选择正确的接口,可以在启动程序时通过设置系统属性来指明要使用的本地地址: ```java System.setProperty("http.bindAddress", "<your_local_ip>"); // 或者针对HTTPS请求 System.setProperty("https.bindAddress", "<your_local_ip>"); ``` 另外也可以考虑使用 `-Djava.net.preferIPv4Stack=true` 参数让JVM优先选用IPv4协议栈,因为某些环境下默认可能会偏好IPv6而导致问题[^1]。 #### 3. 配置防火墙/安全组规则 检查是否有任何防火墙规则阻止了对外部服务发起连接的行为。特别是在云平台上运行的应用,可能还需要调整实例的安全组设置以允许必要的出站流量。 #### 4. 使用HttpClient库自定义SocketFactory 对于更复杂的场景,比如需要精确控制每一个HTTP(S)请求所使用的套接字选项,可以创建自己的`SSLSocketFactory`实现类,并将其应用于Apache HttpClient或其他类似的客户端工具包中: ```java import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.impl.conn.DefaultHttpResponseParser; ... public class CustomSocketFactory implements ConnectionSocketFactory { private final InetAddress localAddress; public CustomSocketFactory(InetAddress addr){ this.localAddress = addr; } @Override public Socket createSocket() throws IOException { Socket socket = new Socket(); socket.setReuseAddress(true); socket.bind(new InetSocketAddress(localAddress, 0)); return socket; } ... } ``` 之后就可以把这个工厂对象传递给HttpClient构建器来进行进一步定制化处理[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值