读取 webapi 2 令牌时读取 HttpResponseMessage.Content 会引发 Newtonsoft.Json.JsonReaderException

Posted

技术标签:

【中文标题】读取 webapi 2 令牌时读取 HttpResponseMessage.Content 会引发 Newtonsoft.Json.JsonReaderException【英文标题】:Reading HttpResponseMessage.Content throws Newtonsoft.Json.JsonReaderException when reading webapi 2 token 【发布时间】:2014-04-03 12:51:44 【问题描述】:

您好,我已经编写了一段代码,应该从 c# 桌面应用程序登录到 WebAPI 2 站点,一切正常,但我得到一个 Newtonsoft.Json.JsonReaderException,消息如下

读取字符串时出错。意外标记:StartObject。路径'',第 1 行,位置 1。

我的代码如下。

static internal async Task<string> GetBearerToken(string siteUrl, string Username, string Password)

  HttpClient client = new HttpClient();
  client.BaseAddress = new Uri(siteUrl);
  client.DefaultRequestHeaders.Accept.Clear();

  HttpContent content = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");

  Task<HttpResponseMessage> responseTask = client.PostAsync("Token", content);
  HttpResponseMessage response = await responseTask;

  if (response.IsSuccessStatusCode)
  
     Task<string> message = response.Content.ReadAsAsync<string>();

     return await message;
  
  else
  
     return null;
  

fiddler 报告的原始响应消息

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 593
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
Set-Cookie: .AspNet.Cookies=vo5b0v_43BLYlfz-rYTZ-TSGi9Rg5jSd9bvKn9693e-Kx3mMI1JVX1Sk-696f_fnPEFPRwFrNWvdMfDWUTWBElfQF3UfcUAxEE5aU5zRgI40sYKapXXnC2ucIiNKCqVsceve0cxNQYVAIr_YhMNjFLRqBX7H3BTPVKGist2AeUkWw6S4VNijx5iQhvWrAvF4xlJSznCiykNqR-QHD_ZLM5-H3GZoghrkvMpr27eXY4mLIqg4lwV2Qah0gQlXnjuWbHHZqLj5HcID1S7_OfPldBE3YqBOR2JxHLITg3yPw3lbXNkHc1UDdG9HExq0faJptz0SBqd8tIeZ7buoJTZ4LHV0TcYSEs4HZ3-Bd84XX7XeWPa5qnTaAJqXaW2FAigD38a9ASr15r5wnzWv9xQxlg; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?RDpcMDYgUHJvamVjdEphZGVcMDIgU2FuZGJveFwwNCBDbGVhbnVwIEFQSSBBY2NvdW50XENsZWFudXBBUElBY2NvdW50XFRva2Vu?=
X-Powered-By: ASP.NET
Date: Sun, 02 Mar 2014 15:22:57 GMT

"access_token":"hM_60CprAm6DqCe7qgte1vsnih2d4j1Uy_FDlgoPkEgS_4u0__4lk5KNd0XysTktOfwMw4ffH3uaRmNaFObVnEY3yWS70hio03azUbCrFKk0VNgj31Y0_zLrd-J0ScZ4vzLdtw7KAXtNfcYySKk1EFtJRB4yYcqvobwORC3eu1VHyYInqy7kBgIhAZYE_NZ3zQrrGerZjy__zCuDdRtXO-klkFtg3dONq7cMP_TBi6xLmBjhXlhzUTKGzOrofijlkyMNHF1rx0CgWjhqEx2rJU8Hakq4Bac1pCqoLaYm91DRSrYO--ff4GWlP5wLeqZAhHIA7t17e2pyZXrUT7V1ExBeCnGkWbWoR8Y-QN8ocT7Q3xjydFd4uWSQD5B-Z1bC-nLpUrtkOGZiukl6J3aCJOqeidY6MEM4TMaJZlIp-Oc","token_type":"bearer","expires_in":1209599,"userName":"Alice",".issued":"Sun, 02 Mar 2014 15:22:57 GMT",".expires":"Sun, 16 Mar 2014 15:22:57 GMT"

我怀疑 json 解析器期望的消息格式与它得到的不同。我不想更改 webapi 站点,所以我可能不得不更改客户端实现。我不需要改变什么,也不需要看哪里。

【问题讨论】:

你说你得到 JsonReaderException,但在你的问题中没有发布任何关于 json 的内容。你如何反序列化响应? 我只使用 ReadAsAsync() 方法。我无处设置特定的解析器。所以我希望 C# 在幕后的某个地方做到这一点。我无法将异常与我的任何代码联系起来。 【参考方案1】:

经过一番激烈的谷歌搜索后,我的代码开始工作了。

我做的第一件事是添加一个额外的类来存储令牌。

class TokenResponseModel

    [JsonProperty("access_token")]
    public string AccessToken  get; set; 

    [JsonProperty("token_type")]
    public string TokenType  get; set; 

    [JsonProperty("expires_in")]
    public int ExpiresIn  get; set; 

    [JsonProperty("userName")]
    public string Username  get; set; 

    [JsonProperty(".issued")]
    public string IssuedAt  get; set; 

    [JsonProperty(".expires")]
    public string ExpiresAt  get; set; 

之后我将代码更改为以下代码。

static internal async Task<TokenResponseModel> GetBearerToken(string siteUrl, string Username, string Password)

    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri(siteUrl);
    client.DefaultRequestHeaders.Accept.Clear();

    HttpContent requestContent = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");

    HttpResponseMessage responseMessage = await client.PostAsync("Token", requestContent);

    if (responseMessage.IsSuccessStatusCode)
    
        string jsonMessage;
        using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
        
            jsonMessage = new StreamReader(responseStream).ReadToEnd();
        

        TokenResponseModel tokenResponse = (TokenResponseModel)JsonConvert.DeserializeObject(jsonMessage, typeof(TokenResponseModel));

        return tokenResponse;
    
    else
    
        return null;
    

我现在可以从客户端的 WebAPI 2 站点获取不记名令牌,以便将其添加到未来的请求中。我希望它对其他人有帮助。

【讨论】:

【参考方案2】:

另一种方法是:

TokenResponseModel tokenResponse = await response.Content.ReadAsAsync<TokenResponseModel>();

【讨论】:

ReadAsAsync 在 System.Net.Http.HttpContent 中似乎不存在,是扩展方法吗? Microsoft.AspNet.WebApi.Client 包包含这种传统方法。或使用JSON deserializing directly instead。【参考方案3】:

错误的对象去脱轨示例

Json 字符串


 "status":"code":"00","description":"Success",
 "data":"userId":"PPP","accessToken":"123131321"

在 vs 中选择性粘贴

public class Rootobject

    public Status status  get; set; 
    public Data data  get; set; 


public class Status

    public string code  get; set; 
    public string description  get; set; 


public class Data

    public string userId  get; set; 
    public string accessToken  get; set; 

代码在这里:

    var client = new HttpClient();
    var url = url_setting;
    var data = new  username = UserName, password = PassWord ;
    var result = client.PostAsync(url, data.AsJson()).Result;            
    var resp = await result.Content.ReadAsAsync<Rootobject>();            
    return resp.data.accessToken;

【讨论】:

以上是关于读取 webapi 2 令牌时读取 HttpResponseMessage.Content 会引发 Newtonsoft.Json.JsonReaderException的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Asp Net Core Web App(不是 WebAPI)中存储令牌

Webapi 2.0如何在访问令牌过期时实现刷新JWT令牌

从 WebAPI 调用的正文中读取 XML 内容在开始时被中断

使用密码或令牌加密 .csv 文件,并在每次用户想要读取文件时询问该密码

WebApi 2 在使用自定义 JWT 令牌进行授权时总是返回 401

获取未捕获的语法错误:意外的令牌:读取 jsonp 响应时