You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.Net中HttpClient调用NetAtmo API GET请求始终报错求助

解决VB.Net中HttpClient调用NetAtmo getmeasure接口失败的问题

我今年74岁,从未接触过Web开发,甚至不清楚HTTP GET与POST的区别。在VB.Net中使用HttpClient调用NetAtmo的getmeasure接口时始终返回错误,但程序生成的URL与NetAtmo官方文档生成的完全一致:

程序生成的URL:https://api.netatmo.com/api/getmeasure?device_id=70%3Aee%3A50%3A12%3A4d%3A12&module_id=02%3A00%3A00%3A12%3A86%3A30&scale=30min&type=temperature&date_begin=1690468462&date_end=1690469662&limit=1024&optimize=false&real_time=true

官方文档生成的URL:https://api.netatmo.com/api/getmeasure?device_id=70%3Aee%3A50%3A12%3A4d%3A12&module_id=02%3A00%3A00%3A12%3A86%3A30&scale=30min&type=temperature&date_begin=1690465917&date_end=1690467117&limit=1024&optimize=false&real_time=true

并且以下CURL命令可正常执行:

curl -X GET "https://api.netatmo.com/api/getmeasure?device_id=70%3Aee%3A50%3A12%3A4d%3A12&scale=30min&type=temperature&date_begin=1690468462&date_end=1690469662&limit=1024&optimize=false&real_time=true" -H "accept: application/json" -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxx|xxxxxxxxxxxxxxxxxxxxxxxx"

Bearer已做替换。我不确定是否需要Authorization,但替换为我生成的URL后CURL能正常工作,问题应该出在HttpClient.GetAsync上。获取刷新token的HTTP POST请求可正常工作,但GET请求一直失败,尝试改用HTTP POST结果也相同。我认为不是AccessToken的问题,因为这类问题会有明确提示。

相关代码

类代码

Public Class ClassHttpPostNetAtmo

  ReadOnly myClientHttp As HttpClient
  ReadOnly parametres As New Dictionary(Of String, String)
  Dim builder As UriBuilder
  Dim query As Specialized.NameValueCollection
  ReadOnly dateUnix As New DateTime(1970, 1, 1, 0, 0, 0, 0)
  Public Sub New()
    myClientHttp = New HttpClient()
  End Sub

  Public Sub ClearPostParametres()
    parametres.Clear()
  End Sub

  Public Sub AddPostParametre(ByVal key As String, ByVal value As String)
    parametres.Add(key, value)
  End Sub

  Public Async Function PostHttp(ByVal RequestUri As String) As Task(Of String)
    Dim content As New FormUrlEncodedContent(parametres)
    Dim response As HttpResponseMessage = Await myClientHttp.PostAsync(RequestUri, content)
    Dim responseString As String = Await response.Content.ReadAsStringAsync()
    Return responseString
  End Function

  Public Async Function RefreshToken(ByVal vRequestUri As String, ByVal vRefresh_token As String, ByVal vClient_id As String, ByVal vClient_secret As String) As Task(Of Dictionary(Of String, String))
    ClearPostParametres()
    AddPostParametre("grant_type", "refresh_token")
    AddPostParametre("refresh_token", vRefresh_token)
    AddPostParametre("client_id", vClient_id)
    AddPostParametre("client_secret", vClient_secret)
    Dim responseString As String = Await PostHttp(String.Concat(vRequestUri, "/oauth2/token"))
    Dim paramRep As New Dictionary(Of String, String)
    Dim str() As String = responseString.Replace("{", "").Replace("}", "").Split(",")
    For Each strPar As String In str
      Dim par() As String = strPar.Split(":")
      paramRep.Add(par(0).Replace("""", ""), par(1).Replace("""", ""))
    Next

    Return paramRep
  End Function


  Public Sub ClearGetParameter(ByVal vRequestUri As String)
    builder = New UriBuilder(vRequestUri) With {
      .Port = -1
    }
    query = HttpUtility.ParseQueryString(builder.Query)
  End Sub

  Public Sub AddGetParametre(ByVal key As String, ByVal value As String)
    If value IsNot Nothing Then
      If key = "type" Then
        Dim tvalue() As String = value.Split(",")
        For Each strVal As String In tvalue
          query.Add(key, strVal)
        Next
      Else
        query.Add(key, value)
      End If
    End If
  End Sub

  Public Async Function GetHttp() As Task(Of String)
    builder.Query = query.ToString()
    Dim url As String = builder.ToString()
    Dim response As HttpResponseMessage = Await myClientHttp.GetAsync(url)
    If response.ReasonPhrase = "ok" Then
      Dim responseString As String = Await response.Content.ReadAsStringAsync()
      Return responseString
    Else
      Throw New Exception(String.Concat("Erreur Http GET : ", response.ReasonPhrase, " Status code = ", response.StatusCode))
    End If

  End Function

  Public Async Function GetWeatherData(ByVal vRequestUri As String, ByVal vDeviceId As String, vDateBegin As DateTime, ByVal vDateEnd As DateTime, Optional ByVal vModuleId As String = Nothing, Optional ByVal vScale As String = "30min", Optional ByVal vType As String = "temperature", Optional ByVal vLimit As String = "1024", Optional ByVal vOptimize As String = "false", Optional ByVal vRealTime As String = "true") As Task
    ClearGetParameter(String.Concat(vRequestUri, "/api/getmeasure"))
    AddGetParametre("device_id", vDeviceId)
    AddGetParametre("module_id", vModuleId)
    AddGetParametre("scale", vScale)
    AddGetParametre("type", vType)
    AddGetParametre("date_begin", CType(((vDateBegin.Subtract(dateUnix)).TotalSeconds), Integer).ToString())
    AddGetParametre("date_end", CType(((vDateEnd.Subtract(dateUnix)).TotalSeconds), Integer).ToString())
    AddGetParametre("limit", vLimit)
    AddGetParametre("optimize", vOptimize)
    AddGetParametre("real_time", vRealTime)
    Dim responseString As String = Await GetHttp()

  End Function

End Class

调用代码

Imports ClassLibraryHttpPostNetAtmo
Imports LibraryDivers
Public Class FrmTestMyLibraryNetAtmo
  Dim ClientId As String
  Dim ClientSecret As String
  Dim myNetAtmo As New ClassHttpPostNetAtmo
  Dim AccessToken As String
  Dim RefreshToken As String
  Private Sub FrmTestMyLibraryNetAtmo_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown

  End Sub

  Private Async Sub BtnTest_Click(sender As Object, e As EventArgs) Handles BtnTest.Click
    If (My.Settings.AccessToken Is Nothing OrElse My.Settings.AccessToken = "") Or
       (My.Settings.RefreshToken Is Nothing OrElse My.Settings.RefreshToken = "") Or
       (My.Settings.DateRefreshToken < Now) Then
      ClientId = ClassDivers.Decode(My.Settings.ClientId, My.Settings.EncodeNumber)
      ClientSecret = ClassDivers.Decode(My.Settings.ClientSecret, My.Settings.EncodeNumber)

      Dim par As Dictionary(Of String, String) = Await myNetAtmo.RefreshToken(My.Settings.RequestUri, My.Settings.RefreshToken, ClientId, ClientSecret)
      AccessToken = par("access_token")
      RefreshToken = par("refresh_token")
      My.Settings.AccessToken = par("access_token")
      My.Settings.RefreshToken = par("refresh_token")
      My.Settings.DateRefreshToken = Now.AddSeconds(par("expire_in")).AddMinutes(-10)
      My.Settings.Save()
    End If
    Await myNetAtmo.GetWeatherData(My.Settings.RequestUri, "70:ee:50:12:4d:12", Now.AddMinutes(-20), Now, vModuleId:="02:00:00:12:86:30")
  End Sub
End Class

问题排查与解决

1. 核心问题:缺失Authorization请求头

你的CURL命令里明确携带了Authorization: Bearer <token>认证头,但当前HttpClient的GET请求完全没有添加这个头。NetAtmo的所有接口都需要通过Bearer Token验证身份,这是导致请求失败的关键原因。

2. 具体修复步骤

步骤1:给ClassHttpPostNetAtmo添加设置认证头的方法

在类中新增以下代码,用于设置Authorization请求头:

Public Sub SetAuthorizationHeader(ByVal accessToken As String)
    myClientHttp.DefaultRequestHeaders.Authorization = New System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken)
End Sub

步骤2:在调用GetWeatherData前设置认证头

修改BtnTest_Click中的代码,在调用GetWeatherData之前添加认证头设置:

' ... 原有刷新token的代码 ...
myNetAtmo.SetAuthorizationHeader(AccessToken)
Await myNetAtmo.GetWeatherData(My.Settings.RequestUri, "70:ee:50:12:4d:12", Now.AddMinutes(-20), Now, vModuleId:="02:00:00:12:86:30")

步骤3:显式设置Accept请求头

虽然HttpClient默认可能会发送Accept头,但显式设置为application/json更稳妥,修改类的构造函数:

Public Sub New()
    myClientHttp = New HttpClient()
    myClientHttp.DefaultRequestHeaders.Accept.Add(New System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"))
End Sub

3. 辅助排查:优化异常信息

修改GetHttp方法,捕获接口返回的具体错误内容,方便后续定位问题:

Public Async Function GetHttp() As Task(Of String)
    builder.Query = query.ToString()
    Dim url As String = builder.ToString()
    Dim response As HttpResponseMessage = Await myClientHttp.GetAsync(url)
    Dim responseString As String = Await response.Content.ReadAsStringAsync()
    If response.IsSuccessStatusCode Then
        Return responseString
    Else
        Throw New Exception(String.Concat("Erreur Http GET : ", response.ReasonPhrase, " Status code = ", response.StatusCode, " Response content: ", responseString))
    End If
End Function

内容的提问来源于stack exchange,提问作者frousset

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 21:15:54