PostAsJsonAsync<string>无法反序列化响应,求排查与修复方案
你遇到的错误'e' is an invalid start of a value是典型的JSON反序列化失败问题,咱们先梳理下你的代码和错误细节:
API代码
public class AuthenticationController : ApiController { public async Task<ActionResult<string>> PostAsync(CreateTokenCommand credentials) { string test= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; return Ok(test); } }
客户端调用代码
public async Task Login(UserCredentials model) { try { var result = await _httpClient.PostJsonAsync<string>("https://localhost:44373/api/authentication", model); } catch (Exception ex) { throw ex; } }
错误信息
'e' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
堆栈跟踪
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, JsonReaderException ex) at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack) at System.Text.Json.JsonSerializer.ReadCore(Type returnType, JsonSerializerOptions options, Utf8JsonReader& reader) at System.Text.Json.JsonSerializer.Deserialize(string json, Type returnType, JsonSerializerOptions options) at System.Text.Json.JsonSerializer.Deserialize<TValue>(string json, JsonSerializerOptions options) at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.d__6`1.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at CheckerApp.WebUI.Services.JWTAuthenticationService.d__3.MoveNext() in D:\MyProjects\CheckerApp\CheckerApp.WebUI\Services\JWTAuthenticationService.cs:line 38
问题根源
当你在API里用return Ok(test);返回字符串时,ASP.NET Core会把它以**纯文本(Plain Text)**的形式返回,响应内容就是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9,没有包裹JSON要求的双引号。
但客户端的PostJsonAsync<string>方法会默认把响应内容当成JSON格式字符串解析,而JSON规范要求字符串必须用双引号包裹。纯文本的token不符合JSON格式,所以序列化器会报错,认为开头的'e'不是有效的JSON值起始字符(JSON有效起始字符为{、[、"、数字、true/false/null)。
修复方案
方案一:修改API返回JSON格式的字符串
让API输出符合JSON规范的内容,有两种实现方式:
返回包含token的匿名对象
ASP.NET Core会自动把对象序列化为JSON格式:public async Task<ActionResult> PostAsync(CreateTokenCommand credentials) { string test= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; return Ok(new { Token = test }); }客户端需要对应调整泛型类型,比如用
dynamic或者定义一个带Token属性的类:var result = await _httpClient.PostJsonAsync<dynamic>("https://localhost:44373/api/authentication", model); string token = result.Token;手动序列化字符串为JSON格式
直接返回包裹双引号的JSON字符串:public async Task<ActionResult> PostAsync(CreateTokenCommand credentials) { string test= "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; return Content(JsonSerializer.Serialize(test), "application/json"); }这样客户端用
PostJsonAsync<string>就能正常解析响应了。
方案二:修改客户端读取纯文本响应
如果不想改动API,客户端可以跳过JSON反序列化,直接读取纯文本内容:
public async Task Login(UserCredentials model) { try { var content = JsonContent.Create(model); var response = await _httpClient.PostAsync("https://localhost:44373/api/authentication", content); response.EnsureSuccessStatusCode(); // 确保请求成功 var result = await response.Content.ReadAsStringAsync(); } catch (Exception ex) { throw ex; } }
内容的提问来源于stack exchange,提问作者Edge of the World

