使用HttpClient从内部WebApi获取数据失败,求排查解决
问题:调用内部WebAPI获取数据失败,后续出现空引用异常
我尝试从内部开发的WebApi获取数据,但一直未成功。该API通过Post请求返回数据,请求体包含复杂筛选条件。此前我曾成功通过Post请求向该API写入数据,但获取数据时遇到瓶颈。
初始请求代码
Public Async Function Request(ByVal client As HttpClient, ByVal content As String) As Task Dim buffer = System.Text.Encoding.UTF8.GetBytes(content) Dim byteContent = New ByteArrayContent(buffer) byteContent.Headers.ContentType = New MediaTypeHeaderValue("application/json") Dim response = Await client.PostAsync(client.BaseAddress, byteContent) Dim result As String = response.Content.ReadAsStringAsync().Result _result = result End Function
为便于使用MSTest测试,结果存储在类变量中。该函数应返回JSON数组,但未返回任何内容,也无错误提示。
对应的MSTest测试方法
<TestMethod()> Public Sub ShouldSuccessfullyInterrodateTheSpenHapi() Dim da = New SPEN.ODSDataPackagerService Dim crit As New HttpCriterion Dim stopped As Boolean Dim jsonString As String = Nothing crit.StartTime = "2022-11-03T00:00:00" crit.EndTime = "2022-11-03T00:30:00" crit.Interval = "30m" crit.TagAttribute = "InstrumentTag" crit.TagFilter = "confidential" crit.Delimiter = "~" crit.ServerName = "SPRODA" '序列化对象为JSON jsonString = da.GetCriteriaJson(crit) Try da.InitialiseSettings() da.Request(da.Clients(0), jsonString) Debug.Print(da.Result) Assert.IsTrue(True) Catch ex As Exception Assert.IsTrue(False) End Try End Sub
请问我忽略了什么?
编辑:出现空引用异常
经过进一步尝试,现在至少能获取到错误信息,代码如下:
Public Async Function GetVoltagesFromPI(ByVal client As HttpClient, ByVal content As String) As Task(Of PIItemList) Dim piItems As PIItemList = New PIItemList Dim buffer = System.Text.Encoding.UTF8.GetBytes(content) Dim byteContent = New ByteArrayContent(buffer) byteContent.Headers.ContentType = New MediaTypeHeaderValue("application/json") Try Dim response As New HttpResponseMessage response = Await client.PostAsync(client.BaseAddress, byteContent) If response.IsSuccessStatusCode Then _result = New PIItemList _result = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result) End If Catch ex As Exception Throw Finally End Try End Function
函数在以下代码处报错:
response = Await client.PostAsync(client.BaseAddress, byteContent)
错误信息:
System.NullReferenceException: 'Object variable or With block
我认为代码逻辑应该没问题,但显然存在实现缺陷,仍未找到解决方案。
问题分析与解决建议
- 异步调用未等待:初始测试方法中调用
da.Request(da.Clients(0), jsonString)时,未用Await等待异步方法完成,导致测试方法可能在请求结束前就读取da.Result,自然拿不到数据。MSTest支持异步测试,需将测试方法改为Async Sub,并使用Await等待请求完成。 - 空引用异常根源:报错行的空引用大概率是
client或client.BaseAddress为Nothing。检查da.InitialiseSettings()是否正确初始化了da.Clients(0),确保HttpClient实例已创建且BaseAddress已设置有效值。 - 同步阻塞异步方法:代码中使用
response.Content.ReadAsStringAsync().Result会阻塞线程,易引发死锁,应改为Await response.Content.ReadAsStringAsync()。 - 缺失错误状态校验:初始代码未检查响应状态码,即使API返回400、500等错误也不会触发异常,无法知晓失败原因。需添加
response.EnsureSuccessStatusCode()抛出HTTP错误异常。 - 反序列化类型缺失:编辑后的代码中
JsonConvert.DeserializeObject未指定目标类型,应写成JsonConvert.DeserializeObject(Of PIItemList)(Await response.Content.ReadAsStringAsync()),才能正确反序列化为PIItemList对象。
修改后的测试方法示例
<TestMethod()> Public Async Sub ShouldSuccessfullyInterrodateTheSpenHapi() Dim da = New SPEN.ODSDataPackagerService Dim crit As New HttpCriterion Dim jsonString As String = Nothing crit.StartTime = "2022-11-03T00:00:00" crit.EndTime = "2022-11-03T00:30:00" crit.Interval = "30m" crit.TagAttribute = "InstrumentTag" crit.TagFilter = "confidential" crit.Delimiter = "~" crit.ServerName = "SPRODA" jsonString = da.GetCriteriaJson(crit) Try da.InitialiseSettings() ' 等待异步请求完成 Await da.Request(da.Clients(0), jsonString) Debug.Print(da.Result) Assert.IsNotNull(da.Result) Catch ex As Exception Assert.Fail($"请求失败: {ex.Message}") End Try End Sub
修改后的请求方法示例
Public Async Function Request(ByVal client As HttpClient, ByVal content As String) As Task If client Is Nothing OrElse client.BaseAddress Is Nothing Then Throw New ArgumentNullException("HttpClient实例或BaseAddress未初始化") End If ' 直接使用StringContent简化代码 Dim byteContent = New StringContent(content, Encoding.UTF8, "application/json") Dim response = Await client.PostAsync(client.BaseAddress, byteContent) ' 校验HTTP请求状态,失败则抛出异常 response.EnsureSuccessStatusCode() Dim result As String = Await response.Content.ReadAsStringAsync() _result = result End Function
内容的提问来源于stack exchange,提问作者Paul Johnson
相关产品推荐
相关产品推荐

