【问题标题】:API return failed using webrequest使用 webrequest 的 API 返回失败
【发布时间】:2019-04-10 00:53:37
【问题描述】:

我试图在我的应用程序中连接一个 api,这个连接以前有效,但现在停止了。

如果我使用任何浏览器或邮递员应用程序,结果是正确的,但是当我使用 webrequest、webclient 或 Visual Studio 中的任何方法时,我收到超时错误。

我放了User Agent,设置超时,使用ssl,每次结果都一样。

测试的端点是:

https://bittrex.com/api/v1.1/public/getmarkets

https://api.coinmarketcap.com/v1/ticker/?limit=1

当我像谷歌一样使用网站进行测试时,此响应有效。

有什么想法吗?

使用 WebRequestHelper 更新

Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Security
Imports System.Security.Cryptography.X509Certificates
Imports System.Text

Public Class WebRequestHelper
    Private m_ResponseUri As Uri
    Private m_StatusCode As HttpStatusCode
    Private m_StatusDescription As String
    Private m_ContentSize As Long
    Private m_WebException As WebExceptionStatus
    Public Property SiteCookies As CookieContainer
    Public Property UserAgent As String = "Mozilla / 5.0(Windows NT 6.1; WOW32; Trident / 7.0; rv: 11.0) like Gecko"
    Public Property Timeout As Integer = 30000
    Public ReadOnly Property ContentSize As Long
        Get
            Return m_ContentSize
        End Get
    End Property

    Public ReadOnly Property ResponseUri As Uri
        Get
            Return m_ResponseUri
        End Get
    End Property

    Public ReadOnly Property StatusCode As Integer
        Get
            Return m_StatusCode
        End Get
    End Property

    Public ReadOnly Property StatusDescription As String
        Get
            Return m_StatusDescription
        End Get
    End Property

    Public ReadOnly Property WebException As Integer
        Get
            Return m_WebException
        End Get
    End Property


    Sub New()
        SiteCookies = New CookieContainer()
    End Sub

    Public Function GetSiteResponse(ByVal siteUri As Uri) As String
        Dim response As String = String.Empty

        ServicePointManager.DefaultConnectionLimit = 50
        Dim maxFWValue As SecurityProtocolType = System.Enum.GetValues(GetType(SecurityProtocolType)).OfType(Of SecurityProtocolType)().Max()
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 Or maxFWValue
        ServicePointManager.ServerCertificateValidationCallback = AddressOf TlsValidationCallback

        Dim Http As HttpWebRequest = WebRequest.CreateHttp(siteUri.ToString)
        With Http
            .Accept = "ext/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
            .AllowAutoRedirect = True
            .AutomaticDecompression = DecompressionMethods.GZip Or DecompressionMethods.Deflate
            .CookieContainer = Me.SiteCookies
            .Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate")
            .Headers.Add(HttpRequestHeader.AcceptLanguage, "en-US,en;q=0.7")
            .Headers.Add(HttpRequestHeader.CacheControl, "no-cache")
            .KeepAlive = True
            .MaximumAutomaticRedirections = 50
            .ServicePoint.Expect100Continue = False
            .ServicePoint.MaxIdleTime = Me.Timeout
            .Timeout = Me.Timeout
            .UserAgent = Me.UserAgent
        End With

        Try
            Using webResponse As HttpWebResponse = DirectCast(Http.GetResponse, HttpWebResponse)
                Me.m_ResponseUri = webResponse.ResponseUri
                Me.m_StatusCode = webResponse.StatusCode
                Me.m_StatusDescription = webResponse.StatusDescription
                Dim contentLength As String = webResponse.Headers.Get("Content-Length")
                Me.m_ContentSize = If(String.IsNullOrEmpty(contentLength), 0, Convert.ToInt64(contentLength))

                Using responseStream As Stream = webResponse.GetResponseStream()
                    If webResponse.StatusCode = HttpStatusCode.OK Then
                        Dim reader As StreamReader = New StreamReader(responseStream, Encoding.Default)
                        Me.m_ContentSize = webResponse.ContentLength
                        response = reader.ReadToEnd()
                        Me.m_ContentSize = If(Me.m_ContentSize = -1, response.Length, Me.m_ContentSize)
                    End If
                End Using
            End Using
        Catch exW As WebException
            If exW.Response IsNot Nothing Then
                Me.m_StatusCode = CType(exW.Response, HttpWebResponse).StatusCode
            End If
            Me.m_StatusDescription = "WebException: " & exW.Message
            Me.m_WebException = exW.Status
        End Try
        Return response
    End Function

    Private Function TlsValidationCallback(sender As Object, CACert As X509Certificate, CAChain As X509Chain, SslPolicyErrors As SslPolicyErrors) As Boolean
        If SslPolicyErrors = SslPolicyErrors.None Then Return True
        Dim Certificate As New X509Certificate2(CACert)

        CAChain.Build(Certificate)
        For Each CACStatus As X509ChainStatus In CAChain.ChainStatus
            If (CACStatus.Status <> X509ChainStatusFlags.NoError) And
                (CACStatus.Status <> X509ChainStatusFlags.UntrustedRoot) Then
                Return False
            End If
        Next
        Return True
    End Function

End Class

并用它来调用类

Dim url As String = "https://bittrex.com/api/v1.1/public/getmarkets"
    Dim uri As New Uri(url)
    Dim wr As New WebRequestHelper
    Dim resp = wr.GetSiteResponse(uri)

【问题讨论】:

  • 两个 API 都返回正确的结果,没有问题。以the code I posted yesterday 为例(出于几乎相同的原因)。我用那个测试了两者。阅读笔记。您的两个站点都需要服务器证书验证回调(在 TLS 握手中很常见)。使用 HttpClient 而不是 WebRequest,您将需要更少的代码。使用 HttpClient 和 .Net Framework 4.7.2+,几乎没有。
  • 您是否完全按照我链接的代码中的方式实现了 WebRequest?我不能让它失败。 This is a recording 在调试时使用该确切代码的过程。
  • 重要的是框架版本和系统版本。该代码使用 FW 4.7.2 进行了测试。 TlsValidationCallback 是否在调试时命中?中间有代理吗?另外,只用ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 尝试它,注释掉现有设置(也许你的系统中有TLS1.3 并且它正在尝试协商它,服务器接受它并且WebRequest 不知道之后该做什么。)。
  • 除非是 AddressOf 导致问题。尝试使用 Lambda 并返回 true(在 3 行中):ServicePointManager.ServerCertificateValidationCallback = Function(s, CA, CAC, pol) Return True End Function
  • 很奇怪。无论如何,由于 VS 2019 确实存在问题(毕竟它是预览版,加上我从未使用过社区版,所以我真的不能说可能缺少什么),你总是可以使用 VS 2017,这是完美的在职的。这两个版本可以毫无问题地存在于同一台机器上。

标签: .net json vb.net api


【解决方案1】:

这是我如何连接到 API 的示例。

首先,根据您的 JSON 结果创建 APIJSONViewModel 来存储 id、name、symbol、rank、price_usd、price_btc 等的值。

        Dim limitnumber as integer = 1
        Dim apiurl As String = "https://api.coinmarketcap.com" 'base url
        Dim apirequesturi As String = "/v1/ticker/?limit=" & limitnumber 'request uri

        Dim resultresponse As List(Of APIJSONViewModel) = New List(Of APIJSONViewModel)

        Try
            Using client As HttpClient = New HttpClient

                ' set url
                client.BaseAddress = New Uri(apiurl)

                ' set json
                client.DefaultRequestHeaders.Accept.Clear()
                client.DefaultRequestHeaders.Accept.Add(New MediaTypeWithQualityHeaderValue("application/json"))

                ' post model as json
                Dim response As HttpResponseMessage = Await client.GetAsync(apirequesturi)

                If response.IsSuccessStatusCode Then

                    ' result get!
                    resultresponse = Await response.Content.ReadAsAsync(Of List(Of APIJSONViewModel))()

                Else
                    r.Errors.Add(response.ReasonPhrase)
                End If

            End Using
        Catch ex As Exception
            r.Errors.Add(ex.Message)
        End Try

【讨论】:

    猜你喜欢
    • 2020-07-11
    • 1970-01-01
    • 2018-07-19
    • 2011-10-11
    • 2016-07-15
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多