【发布时间】:2022-01-23 15:42:13
【问题描述】:
我正在编写一个 .NET Core API,它通过向外部网站发送 API 调用来收集数据并将其保存到数据库中。我已经编写了三种方法,Get_Access_Token、Get_Access 和 Get_Trips 前两个工作文件,但第三个返回 404 URL not found,有趣的是它适用于 Postman 和 Swagger UI。 这是我的代码
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace KnsPortal.Models.MediRouteCustom
{
public class MRHttpClient
{
/// <summary>
/// Get and Set the Access Token - Bearer Token
/// </summary>
private static AccessToken? _accessToken;
/// <summary>
/// Get and Set the list of Access Keys and Funding Sources
/// </summary>
private static List<Access.Access>? _accessKey;
/// <summary>
/// Get the MediRoute Username from config
/// </summary>
private readonly string _clientId;
/// <summary>
/// Get MediRoute Password from config
/// </summary>
private readonly string _clientSecret;
/// <summary>
/// Get the GrantType from config, eg. 'Password'
/// </summary>
private readonly string _grantType;
/// <summary>
/// Get the API Host URL of MediRoute eg. https://external.medirouteapi.com
/// </summary>
private readonly string _apiHost;
/// <summary>
/// Set the number of days you want to collect the trips data, Setting 0 will collect the data of current day
/// </summary>
private readonly int _nextDaysSpan;
/// <summary>
/// Get the instance of HTTPClient
/// </summary>
private readonly HttpClient _httpClient;
/// <summary>
/// Either to included Unscheduled trips or not?
/// </summary>
private readonly bool _includeUnScheduledTrips;
/// <summary>
/// Either to include UnPerformed Trips or not?
/// </summary>
private readonly bool _includeUnperformedTrips;
/// <summary>
/// Either to include Breaks or not?
/// </summary>
private readonly bool _includeBreaks;
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddJsonFile("appsettings.json")
.Build();
//readonly HttpClient httpClient = new HttpClient();
static MRHttpClient()
{
_accessToken = null!;
}
[JsonConstructor]
public MRHttpClient() { }
[JsonConstructor]
public MRHttpClient( HttpClient _client)
{
// Initializing the values on first call
_httpClient = _client ?? throw new ArgumentNullException(nameof(_client));
var config = configuration ?? throw new ArgumentNullException(nameof(configuration));
_clientId = config.GetValue<string>("MediRoute:UserName");
_clientSecret = config.GetValue<string>("MediRoute:Password");
_grantType = config.GetValue<string>("MediRoute:GrantType");
_apiHost = config.GetValue<string>("MediRoute:ApiHost");
_nextDaysSpan = config.GetValue<int>("MediRoute:NextDaySpan");
_includeUnScheduledTrips = config.GetValue<bool>("MediRoute:IncludeUnScheduledTrips");
_includeUnperformedTrips = config.GetValue<bool>("MediRoute:IncludeUnPerformedTrips");
_includeBreaks = config.GetValue<bool>("MediRoute:IncludeBreaks");
}
public async Task<List<MediRoute>> GetTrips(List<Access.Access> _acs, AccessToken _tkn)
{
var _totalTrips = new List<MediRoute>();
if (_acs.Count > 0)
{
for (int i = 0; i < _acs.Count; i++)
{
for (int j = 0; j < _nextDaysSpan + 1; j++)
{
DateTime _date = DateTime.Now.AddDays(j);
// set body parameters required by api
var keyValues = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("api_key", _acs[i].APIKey),
new KeyValuePair<string, string>("includeUnScheduled", _includeUnScheduledTrips.ToString()),
new KeyValuePair<string, string>("includeUnperformed", _includeUnperformedTrips.ToString()),
new KeyValuePair<string, string>("includeBreaks", _includeBreaks.ToString()),
new KeyValuePair<string, string>("date", _date.ToString("yyyy-MM-dd"))
};
// initialize a request message
//API Host: https://external.mediroutesapi.com
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_apiHost + "/api/v1/rides/getRidesByDate"),
Headers =
{
{ HttpRequestHeader.Accept.ToString(), "application/json" },
{ HttpRequestHeader.Authorization.ToString(), "Bearer "+_tkn.access_token }
},
Content = new FormUrlEncodedContent(keyValues)
};
// sent the api call
using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
// collect response
var responseContent = await response.Content.ReadAsStringAsync();
//Deserialize Object from a json format to Object
List<MediRoute> _newTrips = JsonConvert.DeserializeObject<List<MediRoute>>(responseContent);
if (_newTrips.Count > 0)
{
_totalTrips.AddRange(_newTrips);
}
// wait for 2 seconds to send next api call
Thread.Sleep(2000);
}
// wait for 2 seconds to send api calls for another trip provider
Thread.Sleep(2000);
}
return _totalTrips;
}
else return _totalTrips;
}
}
}
谁能指出我做错了什么?我也附上了参数快照。
任何帮助将不胜感激。
【问题讨论】:
-
server 返回 404。客户端无法更改服务器返回的内容。您必须检查服务器做了什么以及为什么它返回 404 - 也许它不喜欢这些参数?也许缺少一些标题?
-
但同样适用于 Postman 和 Swagger。我刚刚复制粘贴了参数。
-
然而服务器不同意。这意味着请求是不同的。人们无法猜测在每种情况下都进行了哪些调用,或者为什么服务器返回 404 而不是例如 401。也许服务器返回 404 是因为令牌不存在。使用 Fiddler 或其他调试代理查看实际的请求和响应是什么,以及它们在每种情况下有何不同
-
@PanagiotisKanavos 提出了一些重要的观点。我还想指出,如果您给我们一个 MCRE (stackoverflow.com/help/minimal-reproducible-example),您会发现人们将能够提供更多帮助 - 您基本上已经复制了大部分应用程序 - 这对我们或您的。尝试将问题隔离到一个易于重现的小代码块 - 这样做的机会是,您自己会注意到问题。如果你不这样做,它会更容易找到帮助
-
@PanagiotisKanavos 感谢您指出正确的方向。
标签: c# api .net-core dotnet-httpclient