首页 文章

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

提问于
浏览
4

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

public async Task<Job> 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<Job>();
    }

    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;
    }

你可以看到我试图添加上面的 Headers ( .WithHeader("Content-Type", "application/json;odata=verbose")

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

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

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

5 回答

  • 1

    This answer is outdated. Upgrade to latest version (2.0 or above) and the problem goes away.

    事实证明real issueSystem.Net.Http API验证标头的方式有关 . 它区分了请求级标头和内容级标头,我将_893608_标头添加到 HttpRequestMessage 对象但是未能验证 Content-Type ,它希望将其添加到 HttpContent 对象中 .

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

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

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

    我_983765_ s AddHeader(s) 实现基于此问题使用 TryAddWithoutValidation .

  • 0
    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<string, object>)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; }
    }
    
  • 4

    我知道你看到了什么API,你通常想要做的是要求服务器在响应中发送详细的OData,而不是声明你在请求中发送它 . 换句话说,您要在 Accept 标头上设置 ;odata=verbose 位,而不是 Content-Type . application/json 应该足够好用于Content-Type,而Flurl会自动为你设置,所以只需尝试这个更改,看看它是否有效:

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

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

    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<Job>();
    

    编辑:发现相关的SO问题:Azure encoding job via REST Fails

  • 0

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

    Upgrade. Flurl.Http 2.0包含以下 Headers 增强功能:

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

    • Headers 现在设置在请求级别,这解决了another known issue .

    • 使用带有对象表示法的 SetHeaders 时, Headers 名称中为underscores in property names will be converted to hyphens,因为 Headers 中的连字符非常常见,所以下划线不是,并且C#标识符中不允许使用连字符 .

    这对你的情况很有用:

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

相关问题