API请求在应用程序中失败,但在浏览器中工作
所以我想从我的Android应用程序中使用Xamarin的API(我无法控制)获取一些信息。API请求在应用程序中失败,但在浏览器中工作
它的工作原理!如果我将生成的链接粘贴到Chrome中,或者使用Chrome扩展邮件管理器,但我无法在我的应用程序中正常工作,我会得到我想要的信息。
应用程序处于poc状态,因此一切都在主它实现了ILocationListener
并请求GPS每3秒更新,但在这里活动是代码的有趣的部分:
public void OnLocationChanged(Location location) {
var lat = location.Latitude;
var lon = location.Longitude;
_lat.Text = "lat: " + lat;
_lon.Text = "lon: " + lon;
// get the vegReference (roadReference) based on the lat & lon
var url = "https://www.vegvesen.no/nvdb/api/vegreferanse/koordinat?lon=" + lon.ToString("") + "&lat=" + lat.ToString("") + "&geometri=WGS84";
// ex: https://www.vegvesen.no/nvdb/api/vegreferanse/koordinat?lon=10.399547&lat=63.354658&geometri=WGS84
var json = new JSONObject(Get(url));
Log.Debug("url", url);
Log.Debug("json", json.ToString());
if (json.GetString("kommuneNr") == "0") return; // bug in API?
var kommuneNr = json.GetString("kommuneNr");
var vegReferanse = json.GetString("visningsNavn");
// get the object id 105 (speed limit) on set vegReference
// API dok: https://www.vegvesen.no/nvdb/apidokumentasjon/#/get/vegobjekter
var url2 = "https://www.vegvesen.no/nvdb/api/v2/vegobjekter/105?vegreferanse=" + vegReferanse.Replace(" ", "") + "&inkluder=lokasjon&segmentering=false";
// ex. https://www.vegvesen.no/nvdb/api/v2/vegobjekter/105?vegreferanse=PV3133HP1m73&inkluder=lokasjon&segmentering=false
// this (url2) is the one that fails
Log.Debug("url2", url2);
var json2 = new JSONObject(Get(url2));
Log.Debug("json2", json2.ToString());
// get the speed limit with the heighest id (this should be the latest one (FYI: speedlimits have changed over the years, all speed limits are in the database for historical reasons(?)))
var objs = json2.GetJSONArray("vegObjekter");
var list = new List<JSONObject>();
// getting a list of possible objects based on the kommuneNr (because for some f*ced up reason the result returns objects in other kommunes aswell...)
for (int i = 0; i < objs.Length() - 1; i++)
{
if (objs.GetJSONObject(i).GetJSONObject("lokasjon").GetJSONArray("kommuner").GetString(0) == kommuneNr)
list.Add(objs.GetJSONObject(i));
}
if (list.Count == 0) return;
var url3 = list[list.Count - 1].GetString("href");
// ex. https://www.vegvesen.no/nvdb/api/v2/vegobjekter/105/276790644
Log.Debug("url3", url3);
var json3 = new JSONObject(Get(url3));
Log.Debug("json3", json3.ToString());
// set the speed-limit to the textview.
var res = json3.GetJSONArray("egenskaper").GetJSONObject(0).GetString("verdi");
_tvSl.Text = res + " km/t";
}
而且Get
- 方法beeing称为OnLocationChanged
内,基本上只获得响应作为一个字符串:
private string Get(string url)
{
var request = WebRequest.Create(url);
var sb = new StringBuilder();
var response = (HttpWebResponse)request.GetResponse();
using (var sr = new StreamReader(response.GetResponseStream()))
{
sb.Append(sr.ReadToEnd());
}
return sb.ToString();
}
从URL2-请求的响应是这样的:
System.Net.WebException: The remote server returned an error: (500) Internal Server Error.
我的问题是;为什么链接(ref url2)在浏览器中运行,而不是在应用程序中运行。
任何帮助或指针在这个问题将不胜感激! 另请参见:链接到GitHub上的项目:https://github.com/Nemeas/alfaOmega
好吧,经过大量的试验和错误,我发现问题是有一个丢失的标题; accept: application/json
(看起来这只是这个api(?)的v2的情况)。我尝试使用WebRequest
添加标题,但每当我到达添加标题的行时都会收到错误。然而,还有另一个WebRequest
,名为HttpWebRequest
,其中accept
作为属性而不是通过列表公开,并且这是有效的。所以我必须做的唯一的改变是在Get
方法,结果是这样的:
public static string Get(string url)
{
// casting request to HttpWebRequest to expose Accept as a property
var request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "application/json";
var sb = new StringBuilder();
// getting the response
var response = (HttpWebResponse)request.GetResponse();
using (var sr = new StreamReader(response.GetResponseStream()))
{
sb.Append(sr.ReadToEnd());
}
var res = sb.ToString();
// returning the response as a string
return res;
}
看起来你是对的,一个_missing_ Accept头确实被解释为一个无效的Accept值,而不是默认为*/*。感谢您发现这个错误。 – matsa
嘿!这里的API作者之一。我也想深入了解这个案例。我无法在这个时候运行你的Xamarin代码,但我想指导你编程参考。我们已经为Java平台发布了一个开源客户端。源代码可能会给你的索姆提示https://github.com/nvdb-vegdata/nvdb-api-client – matsa
@matsa所以我实际上(最终)通过添加'接受:应用程序/ json的工作得到的东西工作请求。但是我不得不在'Get'方法中使用'HttpWebRequest',因为'request.Headers.Add(HttpRequestHeader.Accept,“application/json”)'不起作用(它一直说我必须提供一个有效的属性值,或者类似的东西。还尝试使用字符串值“accept”而不是Enum/Const(?)HttpRequestHeader.Accept),但是'HttpWebRequest'暴露了'accept'作为一个属性,如下所示:'request.Accept = “应用/ JSON”'。这在第一个url中并不需要apiv1 – Nemeas