从 JsonReader 读取 JObject 时出错。路径 '',第 0 行,位置 0。”

问题描述 投票:0回答:1

我使用以下代码在 Visual Studio 2022 中调用 post 接口:

private List<Token> LoginToken(string username, string password)
{
 string api = "";
 List<Token> list = new List<Token>();
 string url = "";
 Dictionary<string, string> dics = new Dictionary<string, string>
 {
   { "username", username },
   { "password", password },
   { "loginType", "account" },
   { "grantType", "password" }
 };
 Task<string> task = Api.InvokeWebapi(url, api, "POST", dics);
 string result = task.Result;

 if (result != null)
 {
     JObject jsonObj = null;
     jsonObj = JObject.Parse(result);
     DataInfo info = new DataInfo();
     info.statusCode = Convert.ToInt32(jsonObj["code"]);
     info.message = jsonObj["message"].ToString();
     if (info.statusCode == 1)
     {
         JArray jlist = JArray.Parse(jsonObj["data"].ToString());
         for (int i = 0; i < jlist.Count; ++i)
         {
             Token ver = new Token();
             JObject tempo = JObject.Parse(jlist[i].ToString());
             ver.access_token = tempo["access_token"].ToString();
             ver.token_type = tempo["token_type"].ToString();
             ver.expires_in = Convert.ToInt32(tempo["expires_in"]);
             ver.scope = tempo["scope"].ToString();
             ver.name = tempo["name"].ToString();
             ver.my_Corp = tempo["my_Corp-Code"].ToString();
             ver.userId = Convert.ToInt32(tempo["userId"]);
             ver.username = tempo["username"].ToString();
             ver.jti = tempo["jti"].ToString();
             list.Add(ver);
         }
     }
 }
 return list;
}


public async Task<string> InvokeWebapi(string url, string api, string type, Dictionary<string, string> dics)
{
    string result = string.Empty;
    HttpClient client = new HttpClient();
    client.DefaultRequestHeaders.Add("Authorization", "Basic 1111");
    client.BaseAddress = new Uri(url);

    client.Timeout = TimeSpan.FromSeconds(510);

    if (type.ToLower() == "put")
    {
        HttpResponseMessage response;
        if (dics.Keys.Contains("input"))
        {
            if (dics != null)
            {
                foreach (var item in dics.Keys)
                {
                    api = api.Replace(item, dics[item]).Replace("{", "").Replace("}", "");
                }
            }
            var contents = new StringContent(dics["input"], Encoding.UTF8, "application/json");
            response = client.PutAsync(api, contents).Result;
            if (response.IsSuccessStatusCode)
            {
                result = await response.Content.ReadAsStringAsync();
                return result;
            }
            return result;
        }

        var content = new FormUrlEncodedContent(dics);
        response = client.PutAsync(api, content).Result;
        if (response.IsSuccessStatusCode)
        {
            result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }
    else if (type.ToLower() == "post")
    {
        var content = new FormUrlEncodedContent(dics);

        HttpResponseMessage response = client.PostAsync(api, content).Result;
        if (response.IsSuccessStatusCode)
        {
            result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }
    else if (type.ToLower() == "get")
    {
        HttpResponseMessage response = client.GetAsync(api).Result;

        if (response.IsSuccessStatusCode)
        {
            result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }
    else
    {
        return result;
    }
    return result;
}
}

我在Visual Studio 2022中使用上面的代码调用post接口,但是

jsonObj = JObject.Parse(result);
中报的错误是
Newtonsoft.Json.JsonReaderException: "Error reading JObject from JsonReader. Path '', line 0, position 0."

更新:

我捕获了报错时api的响应:

{StatusCode: 415, ReasonPhrase: 'Unsupported Media Type', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Pragma: no-cache
X-Frame-Options: DENY
Referrer-Policy: no-referrer
Cache-Control: no-store, must-revalidate, no-cache, max-age=0
Date: Wed, 17 Jul 2024 08:47:38 GMT
Server: nginx/1.24.0
Content-Type: application/json
Expires: 0
}}
c# httpclient
1个回答
0
投票

InvokeWebApi
方法充满了错误,将FORM内容发送到显然需要JSON并隐藏错误的服务,如果出现问题则返回空字符串。由于内容不正确,远程服务拒绝调用,但调用代码仍然尝试反序列化空字符串,从而导致错误。

真正的解决方案是用适当的调用完全替换

InvokeWebApi
。首先,HttpClient 是线程安全的并且可以重用。每次创建一个新的都是一个重大错误,导致套接字耗尽。

HttpClient 实例应该是方法的字段或参数。在 ASP.NET Core 中,最简单的方法是使用 DI 注入。它所需要的只是一个

builder.Services.AddHttpClient()
调用,并将
HttpClient
作为构造函数参数添加到需要它的控制器或服务中。

builder.Services.AddHttpClient(client=>{
    client.DefaultRequestHeaders.Add("Authorization", "Basic 1111");
    client.BaseAddress = new Uri(siteUrl);
});

无论 HttpClient 来自哪里,整个

LoginToken
方法都可以简化为这样:

async Task<List<Token>> LoginToken(string username, string password)
{
    var request = new {
       username=username,
       password=password ,
       loginType="account",
       grantType="password"
    };

    var resp=await _client.PostAsJsonAsync(relativeUrl,request);
    if (!resp.IsSuccessStatusCode)
    {
        //Actually handle the problem, the application can't continue without a token
        _logger.LogError("Token call failed with {code}:{reason}",resp.StatusCode,resp.ReasonPhrase);
        throw new Exception(.....);
    }
    DataInfo info=await resp.Content.ReadAsJsonAsync<DataInfo>();
    if (info.Code == "0001") //Or whatever the success code is
    {
        return info.Data;
    }
    else 
    {
        _logger.LogError("Token retrieval failed with {code}:{message}",info.statusCode,info.message);
        //Actually do something about the error. 
        //The application can't proceed without a login token
    }
}

PostAsJsonAsync方法会将请求对象直接序列化为 JSON 格式的请求流,并确保使用正确的内容类型。

代码假设

DataInfo
Token
对象与响应 JSON 匹配,正如它们应该的那样。例如:

public class DataInfo
{
    public int Code {get;set;}
    public string Message {get;set;}
    List<Token> Data{get;set;}
}

public class DataInfo<T>
{
    public int Code {get;set;}
    public string Message {get;set;}
    List<T> Data {get;set;}
}

[JsonPropertyName("code")]
属性可用于将
code
映射到名为
StatusCode

的属性
public class DataInfo<T>
{
    [JsonPropertyName("code")]
    public int StatusCode {get;set;}
    public string Message {get;set;}
    List<T> Data {get;set;}
}
© www.soinside.com 2019 - 2024. All rights reserved.