来自 Json post 的错误 400(错误请求)包含双精度数字
Error 400 (Bad Request) from Json post containing double-precision numbers
我将定期 post 发送到服务器,该服务器将结果数据存储在数据库中。很多时候,服务器返回 400 错误,这似乎意味着 post 格式错误。但我可以告诉(从正确的数据存储在数据库中的事实)有时服务器已经接受了数据。
Json 非常简单,而且每次都差不多,例如
{“纬度”:50.2905,“经度”:5.04548,“recorded_at”:“20200925 21:07:31”,“所有者”:1}。
有时它会被无误地接受。如果通过 WiFi/Broadband 或 4G 发送数据,则会发生错误。
发送数据的(Xamarin)代码如下:
private string UploadResult(WebClient client, double lat, double lng, DateTime t)
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
lat = Math.Round(lat, 5);
lng = Math.Round(lng, 5);
json = string.Format("{{\"latitude\":{0},\"longitude\":{1},\"recorded_at\":\"{2}\",\"owner\":{3}}}",
lat, lng, DBTime(t), MyLocation.owner);
Uri uri = new Uri(UrlBase.urlBase + "SaveLocation");
string result = client.UploadString(uri, json);
return result;
}
我无法访问服务器进行调试,只能查看数据库条目。它是一个将数据存储在 MSSQL 数据库中的 WCF 服务,lat/longs 存储为 decimal(10,6)。我相当确定问题是最近出现的,即使相关代码没有更改 - 我之前没有收到这些错误(无论如何都不明显)。
我在这里做了很多搜索并尝试了很多代码更改,所有这些都没有效果。我在不同版本的 Visual Stuio、Xamarin 和 Android API 级别上遇到了同样的问题。
最终我尝试在 posting 之前降低纬度和经度的精度,即
lat = Math.Round(lat, 1);
lng = Math.Round(lng, 1);
还有 Bingo!,一切都很好(当然除了我的数据库的准确性)。具有 2 位或更多小数位会返回错误。
显然可以将服务器代码更改为仅接受整数,并以不同的方式发送数据,但这会很棘手。我可以在客户端代码中更改什么来解决这个问题?
[稍后]
我尝试为十进制数字添加正确的字符串格式
json = string.Format("{{\"latitude\":{0:0.0000},\"longitude\":{1:0.0000},\"recorded_at\":\"{2}\",\"owner\":{3}}}", ....
但这没有什么区别。有趣的是,我还尝试将数字作为字符串发送
json = string.Format("{{\"latitude\":\"{0}\",\"longitude\":\"{1}\",\"recorded_at\":\"{2}\",\"owner\":{3}}}", ......
这同样被接受,但错误频率相同。据我了解,数字数据应该作为字符串被拒绝。
通过将 WebClient 更改为 HttpClient 解决了这个问题。我知道 WebClient 是老技术,但我很久以前就写了原始代码,它确实可以正常工作。
private async Task<HttpResponseMessage> UploadResult(double lat, double lng, DateTime t)
{
lat = Math.Round(lat, 5);
lng = Math.Round(lng, 5);
using (HttpClient httpClient = new HttpClient())
{
string json = string.Format("{{\"latitude\":{0:0.00000},\"longitude\":{1:0.00000},\"recorded_at\":\"{2}\",\"owner\":{3}}}",
lat, lng, DBTime(t), Location.owner);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
Uri uri = new Uri(UrlBase.urlBase + "SaveLocation");
try
{
response = await httpClient.PostAsync(uri, content);
}
catch (Exception ex)
{
if (response == null)
{
response = new HttpResponseMessage();
}
response.StatusCode = HttpStatusCode.InternalServerError;
response.ReasonPhrase = string.Format("Post failed: {0}", ex.Message);
}
return response;
}
}
也需要用await调用这个函数。
我将定期 post 发送到服务器,该服务器将结果数据存储在数据库中。很多时候,服务器返回 400 错误,这似乎意味着 post 格式错误。但我可以告诉(从正确的数据存储在数据库中的事实)有时服务器已经接受了数据。 Json 非常简单,而且每次都差不多,例如
{“纬度”:50.2905,“经度”:5.04548,“recorded_at”:“20200925 21:07:31”,“所有者”:1}。
有时它会被无误地接受。如果通过 WiFi/Broadband 或 4G 发送数据,则会发生错误。 发送数据的(Xamarin)代码如下:
private string UploadResult(WebClient client, double lat, double lng, DateTime t)
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
lat = Math.Round(lat, 5);
lng = Math.Round(lng, 5);
json = string.Format("{{\"latitude\":{0},\"longitude\":{1},\"recorded_at\":\"{2}\",\"owner\":{3}}}",
lat, lng, DBTime(t), MyLocation.owner);
Uri uri = new Uri(UrlBase.urlBase + "SaveLocation");
string result = client.UploadString(uri, json);
return result;
}
我无法访问服务器进行调试,只能查看数据库条目。它是一个将数据存储在 MSSQL 数据库中的 WCF 服务,lat/longs 存储为 decimal(10,6)。我相当确定问题是最近出现的,即使相关代码没有更改 - 我之前没有收到这些错误(无论如何都不明显)。
我在这里做了很多搜索并尝试了很多代码更改,所有这些都没有效果。我在不同版本的 Visual Stuio、Xamarin 和 Android API 级别上遇到了同样的问题。
最终我尝试在 posting 之前降低纬度和经度的精度,即
lat = Math.Round(lat, 1);
lng = Math.Round(lng, 1);
还有 Bingo!,一切都很好(当然除了我的数据库的准确性)。具有 2 位或更多小数位会返回错误。
显然可以将服务器代码更改为仅接受整数,并以不同的方式发送数据,但这会很棘手。我可以在客户端代码中更改什么来解决这个问题?
[稍后] 我尝试为十进制数字添加正确的字符串格式
json = string.Format("{{\"latitude\":{0:0.0000},\"longitude\":{1:0.0000},\"recorded_at\":\"{2}\",\"owner\":{3}}}", ....
但这没有什么区别。有趣的是,我还尝试将数字作为字符串发送
json = string.Format("{{\"latitude\":\"{0}\",\"longitude\":\"{1}\",\"recorded_at\":\"{2}\",\"owner\":{3}}}", ......
这同样被接受,但错误频率相同。据我了解,数字数据应该作为字符串被拒绝。
通过将 WebClient 更改为 HttpClient 解决了这个问题。我知道 WebClient 是老技术,但我很久以前就写了原始代码,它确实可以正常工作。
private async Task<HttpResponseMessage> UploadResult(double lat, double lng, DateTime t)
{
lat = Math.Round(lat, 5);
lng = Math.Round(lng, 5);
using (HttpClient httpClient = new HttpClient())
{
string json = string.Format("{{\"latitude\":{0:0.00000},\"longitude\":{1:0.00000},\"recorded_at\":\"{2}\",\"owner\":{3}}}",
lat, lng, DBTime(t), Location.owner);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
Uri uri = new Uri(UrlBase.urlBase + "SaveLocation");
try
{
response = await httpClient.PostAsync(uri, content);
}
catch (Exception ex)
{
if (response == null)
{
response = new HttpResponseMessage();
}
response.StatusCode = HttpStatusCode.InternalServerError;
response.ReasonPhrase = string.Format("Post failed: {0}", ex.Message);
}
return response;
}
}
也需要用await调用这个函数。