如何更改FLURL客户端的HTTP请求内容类型?

我正在使用flurl提交HTTP请求,这非常有用。 现在我需要将一些请求的“ Content-Type”标题更改为“application / json; odata = verbose”

public async Task AddJob() { var flurlClient = GetBaseUrlForGetOperations("Jobs").WithHeader("Content-Type", "application/json;odata=verbose"); return await flurlClient.PostJsonAsync(new { //Some parameters here which are not the problem since tested with Postman }).ReceiveJson(); } private IFlurlClient GetBaseUrlForOperations(string resource) { var url = _azureApiUrl .AppendPathSegment("api") .AppendPathSegment(resource) .WithOAuthBearerToken(AzureAuthentication.AccessToken) .WithHeader("x-ms-version", "2.11") .WithHeader("Accept", "application/json"); return url; } 

您可以看到我如何尝试添加上面的标题( .WithHeader("Content-Type", "application/json;odata=verbose")

不幸的是,这给了我以下错误:

“InvalidOperationException:Misused header name。确保请求标头与HttpRequestMessage一起使用,响应标头与HttpResponseMessage一起使用,内容标头与HttpContent对象一起使用。”

我也尝试了flurl的“ConfigureHttpClient”方法,但无法找到设置内容类型标头的方式/位置。

这个答案已经过时了。 升级到最新版本 (2.0或更高版本 ),问题就消失了。

事实certificate, 真正的问题与System.Net.Http API如何validation标头有关。 它区分了请求级标头和内容级标头,我总是觉得有点奇怪,因为原始HTTP没有这样的区别(除了可能在多部分方案中)。 Flurl的WithHeader将标头添加到HttpRequestMessage对象,但是对Content-Typevalidation失败,它希望将其添加到HttpContent对象中。

那些API确实允许你跳过validation,虽然Flurl没有直接暴露它,你可以很容易地进入引擎盖,而不会破坏流畅的链:

 return await GetBaseUrlForGetOperations("Jobs") .ConfigureHttpClient(c => c.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;odata=verbose")) .PostJsonAsync(new { ... }) .ReceiveJson(); 

这可能是做你需要的最好的方法,并且仍然利用Flurl的优点,即不必直接处理序列化, HttpContent对象等。

我正在考虑改变Flurl的AddHeader(s)实现, TryAddWithoutValidation根据此问题使用TryAddWithoutValidation

 public static class Utils { public static IFlurlClient GetBaseUrlForOperations(string resource) { var _apiUrl = "https://api.mobile.azure.com/v0.1/apps/"; var url = _apiUrl .AppendPathSegment("Red-Space") .AppendPathSegment("HD") .AppendPathSegment("push") .AppendPathSegment("notifications") .WithHeader("Accept", "application/json") .WithHeader("X-API-Token", "myapitocken"); return url; } public static async Task Invia() { FlurlClient _client; PushMessage pushMessage = new PushMessage(); pushMessage.notification_content = new NotificationContent(); try { var flurClient = Utils.GetBaseUrlForOperations("risorsa"); // News news = (News)contentService.GetById(node.Id); //pushMessage.notification_target.type = ""; pushMessage.notification_content.name = "A2"; // pushMessage.notification_content.title = node.GetValue("TitoloNews").ToString(); pushMessage.notification_content.title = "Titolo"; pushMessage.notification_content.body = "Contenuto"; var jobInJson = JsonConvert.SerializeObject(pushMessage); var json = new StringContent(jobInJson, Encoding.UTF8); json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); dynamic data2 = await flurClient.PostAsync(json).ReceiveJson(); var expandoDic = (IDictionary)data2; var name = expandoDic["notification_id"]; Console.WriteLine(name); } catch (FlurlHttpTimeoutException ex) { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType + " " + ex); } catch (FlurlHttpException ex) { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType + " " + ex); if (ex.Call.Response != null) Console.WriteLine("Failed with response code " + ex.Call.Response.StatusCode); else Console.WriteLine("Totally failed before getting a response! " + ex.Message); } catch (Exception ex) { Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType + " " + ex); } } } public class NotificationTarget { public string type { get; set; } } public class CustomData {} public class NotificationContent { public string name { get; set; } public string title { get; set; } public string body { get; set; } public CustomData custom_data { get; set; } } public class PushMessage { public NotificationTarget notification_target { get; set; } public NotificationContent notification_content { get; set; } } 

我不是OData专家,我不知道你在调用什么API(SharePoint?),但基于我见过的大多数示例,你通常想要做的是要求服务器发送详细的OData响应,而不是声明您在请求中发送它。 换句话说,您要在Accept标头上设置;odata=verbose位,而不是Content-Typeapplication/json应该足够好用于Content-Type,而Flurl会自动为你设置,所以只需尝试这个更改,看看它是否有效:

 .WithHeader("Accept", "application/json;odata=verbose"); 

我发现的评论和另一篇文章(当我再次找到它时会添加参考文献)指出了正确的方向。 我的问题的解决方案如下:

  var jobInJson = JsonConvert.SerializeObject(job); var json = new StringContent(jobInJson, Encoding.UTF8); json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json; odata=verbose"); var flurClient = GetBaseUrlForOperations("Jobs"); return await flurClient.PostAsync(json).ReceiveJson(); 

编辑:找到相关的SO问题: Azure编码作业通过REST失败

我可以发布同一个问题的3个答案吗? 🙂

升级。 Flurl.Http 2.0包含以下对标题的增强:

  1. WithHeader(s)现在使用了引擎盖下的TryAddWithoutValidation 。 仅凭这一变化,OP的代码将按原始发布的方式运行。

  2. 标题现在设置在请求级别,这解决了另一个已知问题 。

  3. 使用带有对象表示法的SetHeaders时,属性名称中的下划线将在标题名称中转换为连字符 ,因为标题中的连字符非常常见,下划线不是,并且C#标识符中不允许使用连字符。

这对你的情况很有用:

 .WithHeaders(new { x_ms_version = "2.11", Accept = "application/json" });