无法反序列化 text/html json 响应

Posted

技术标签:

【中文标题】无法反序列化 text/html json 响应【英文标题】:Failing to deserialise a text/html json response 【发布时间】:2021-08-31 06:10:33 【问题描述】:

我正在与旧 API 进行集成,由于某种原因,该 API 将 json 数据作为文本/html 响应返回。我曾尝试在 C# 中使用 Newtonsoft 反序列化此字符串,并使用包括 JSON.parse() 在内的各种 javascript 库,但都失败了。

实际响应看起来像一个有效的 json 对象,但它无法反序列化:

"err":201,"errMsg":"We cannot find your account.\uff01","data":[],"selfChanged":

我认为存在一些特殊字符,或者实际响应的格式是我的任何解析器都无法反序列化开箱即用的格式。我附上了各种语言的各种代码示例,包括 curl。如果有人可以帮助反序列化 C# 中的响应对象或为我指明正确的方向,我将不胜感激。

C#

var client = new RestClient("http://47.89.182.211:8080/index.php/account/login");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("appVersion", "0");
request.AddParameter("password", "xxxxxx");
request.AddParameter("platform", "5");
request.AddParameter("platformId", "xxx@xxx.com");
request.AddParameter("userType", "4");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Java

Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.post("http://47.89.182.211:8080/index.php/account/login")
  .header("Accept", "application/json")
  .header("Content-Type", "application/x-www-form-urlencoded")
  .field("appVersion", "0")
  .field("password", "xxxxxx")
  .field("platform", "5")
  .field("platformId", "xxx@xxx.com")
  .field("userType", "4")
  .asString();

Javascript

var data = "appVersion=0&password=xxxxxx&platform=5&platformId=xxx%40xxx.com&userType=4";

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() 
  if(this.readyState === 4) 
    console.log(this.responseText);
  
);

xhr.open("POST", "http://47.89.182.211:8080/index.php/account/login");
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.send(data);

卷曲

curl --location --request POST 'http://47.89.182.211:8080/index.php/account/login' \
--header 'Accept: application/json' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'appVersion=0' \
--data-urlencode 'password=xxxxxx' \
--data-urlencode 'platform=5' \
--data-urlencode 'platformId=xxx@xxx.com' \
--data-urlencode 'userType=4'

如果您能够将响应解析为有效的 json 对象或将其反序列化为 C# 或 Java 对象,请告诉我。

【问题讨论】:

第一个字符就是问题所在。这是一个零宽度的空间:compart.com/de/unicode/U+FEFF 如果你删除第一个字符,你可以解析其余的就好了。 【参考方案1】:

这个 c# 代码对我有用。我无法解释遇到的空字符问题。如果是这样的话,我不得不想象你正在使用的网站会给他们所有的用户带来麻烦。无论如何,这里有一些尝试:

HttpClient hc = new HttpClient();
Dictionary<string, string> body = new Dictionary<string, string>   "appversion", "0" ,  "password", "xxxxx" ,  "platform", "5" ,  "platformId", "xxx.xxx.com" , "userType", "4";
HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Post, "http://47.89.182.211:8080/index.php/account/login");
msg.Headers.Add("Accept", "application/json");
FormUrlEncodedContent fuec = new FormUrlEncodedContent(body);
msg.Content = fuec;
var result = await hc.SendAsync(msg);
string response = await result.Content.ReadAsStringAsync();
Console.WriteLine(response[0]);
Console.WriteLine(response);
var obj = Newtonsoft.Json.Linq.JObject.Parse(response);
Console.WriteLine(obj["err"]);

【讨论】:

谢谢,这绝对适用于 C# 开头的空白字符有点令人困惑。 @pattywoddle 太棒了!现在我真的很好奇有什么区别。【参考方案2】:

这可以在 C# 中通过自定义 JsonMediaTypeFormatter(来自 NuGet 包 Microsoft.AspNet.WebApi.Client)来完成,如下所示:

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Get, "UrlToLoginPageHere");
using var response = await client.SendAsync(request);

var formatters = new[]

    new JsonMediaTypeFormatter
    
        SupportedMediaTypes =  new MediaTypeHeaderValue("text/html") ,
    ,
;
var result = await response.Content.ReadAsAsync<Rootobject>(formatters);

Rootobject 是代表 JSON 模型的对象(例如,在 Visual Studio 中,选择编辑 > 选择性粘贴 > 将 JSON 粘贴为类)。

【讨论】:

这是否解决了第一个字符是不间断零宽度空格的问题? @ChrisG 您在哪里体验过零宽度空间?我在 Postman 中运行了请求,但没有得到那个字符。 @Crowcoder 我使用节点获取了 URL 并记录了 replyText.charCodeAt(0)。它在 Postman 或浏览器中是不可见的,因为它是一个零宽度字符:pastebin.com/5HwPYk9R @ChrisG 你在做某事。我刚刚用C#打印了字符,第一个位置肯定有一个字符。我将尝试删除它,看看它是否有效。 @ChrisG 我现在用 c# 实现了它,并且 JSON.NET 将响应反序列化为 json 没有问题。 [0] 处的字符是“”

以上是关于无法反序列化 text/html json 响应的主要内容,如果未能解决你的问题,请参考以下文章

无法反序列化 Json 文件虽然得到了响应

Json.JsonSerializationException : 无法反序列化当前 JSON 对象

WCF 无法反序列化 JSON 请求

以“TryParse”方式反序列化 json

Json.NET:将嵌套数组反序列化为强类型对象

将Json字符串反序列化为对象java