在我发送大约 1500-1700 个网络请求后(始终在该范围内),我收到此错误:
TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_NOT_DONE
重新启动 Unity 会“刷新”配额,我可以再次发送大约相同数量的请求。
我正在构建一个网络爬虫,我需要发送大约 14000 个请求。 每个请求之间都有延迟,我最多同时发送 5 个请求,以避免服务器过载。
我也尝试了以下网站进行测试,但得到了同样的错误: https://httpbin.org/
这是我的 HttpClient:
private static readonly Lazy<HttpClient> httpClient = new(() => new HttpClient(new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
ClientCertificateOptions = ClientCertificateOption.Automatic,
SslProtocols = SslProtocols.None
})
{
BaseAddress = new Uri("https://yugioh.fandom.com/"),
Timeout = TimeSpan.FromSeconds(HTTPCLIENT_TIMEOUT),
DefaultRequestHeaders =
{
ConnectionClose = true
}
});
更改 HttpClient 中的设置(或根本没有自定义设置)并不能解决问题。
我读到 UnityWebRequest 可能没有这些问题,但它只能从主线程调用,我不想重构所有内容以使用协程。
编辑: 这是我用于发送请求和读取内容流的代码。
internal static async Task<CustomHttpStatusCode> DownloadAsync(URL _URL, Func<string, Task> _ProcessLine, Func<bool> _StopCondition, CancellationToken _CancellationToken)
{
using var _cancellationTokenSource = new CancellationTokenSource();
using var _linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_CancellationToken, _cancellationTokenSource.Token);
var (_statusCode, _contentStream) = await DownloadAsStreamAsync(_URL, _linkedCancellationTokenSource.Token);
if (_contentStream == null)
{
return _statusCode;
}
using (var _streamReader = new StreamReader(_contentStream))
{
while (await _streamReader.ReadLineAsync() is {} _currentLine)
{
await _ProcessLine(_currentLine);
if (_StopCondition())
{
_cancellationTokenSource.Cancel();
return CustomHttpStatusCode.Stopped;
}
}
}
return _statusCode;
}
private static async Task<(CustomHttpStatusCode StatusCode, Stream? ContentStream)> DownloadAsStreamAsync(URL _URL, CancellationToken _CancellationToken)
{
var _semaphoreAcquired = false;
var _attempt = 1;
var _httpStatusCode = CustomHttpStatusCode.Null;
Stream? _contentStream = null;
do
{
try
{
await Task.Delay(1000, _CancellationToken);
await semaphoreSlim.Value.WaitAsync(_CancellationToken);
_semaphoreAcquired = true;
// I can't add a "using" here since the stream would already be disposed when i try to access it in "DownloadAsync".
var _response = await httpClient.Value.GetAsync(_URL.AbsoluteUri, HttpCompletionOption.ResponseHeadersRead, _CancellationToken);
_httpStatusCode = _response.EnsureSuccessStatusCode().StatusCode.ToCustomHttpStatusCode();
_contentStream = await _response.Content.ReadAsStreamAsync();
return (_httpStatusCode, _contentStream);
}
catch (TaskCanceledException) when (_CancellationToken.IsCancellationRequested) { /* Expected behavior. */ }
catch (Exception _exception)
{
Debug.LogException(_exception.CustomMessage($"Download attempt [{_attempt}] aborted: {_URL.Bold()} [{_httpStatusCode}]"));
await Task.Delay(5000 * _attempt++, _CancellationToken);
}
finally
{
if (_semaphoreAcquired)
{
semaphoreSlim.Value.Release();
}
}
} while (!_CancellationToken.IsCancellationRequested && _attempt <= 3);
return (_httpStatusCode, _contentStream);
}
这是Unity中的一个错误,错误报告如下: issuetracker.unity3d.com