【问题标题】:How to change the HTTP Request Content Type for FLURL Client?如何更改 FLURL 客户端的 HTTP 请求内容类型?
【发布时间】:2017-11-14 20:44:30
【问题描述】:

我正在使用 flurl 提交 HTTP 请求,这非常有用。现在我需要将一些请求的“Content-Type”标头更改为“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;
    }

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

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

"InvalidOperationException: 错误的标头名称。确保请求 标头与 HttpRequestMessage 一起使用,响应标头与 HttpResponseMessage,以及带有 HttpContent 对象的内容标头。”

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

【问题讨论】:

标签: c# http-headers flurl


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

我找到的 cmets 和另一个帖子(当我再次找到它时会添加参考)为我指明了正确的方向。 我的问题的解决方案如下:

        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

【讨论】:

  • 那行得通。我发布了一个您可能更喜欢的替代答案。
【解决方案3】:

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

原来real issueSystem.Net.Http API 验证标头的方式有关。它区分了请求级标头和内容级标头,我一直觉得这有点奇怪,因为原始 HTTP 没有这种区别(可能在多部分场景中除外)。 Flurl 的 WithHeader 将标头添加到 HttpRequestMessage 对象,但无法验证 Content-Type,它希望将其添加到 HttpContent 对象中。

这些 API 确实允许您跳过验证,虽然 Flurl 没有直接公开它,但您可以很容易地进入底层,而不会破坏 fluent 链:

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

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

基于此问题,我强烈考虑将 Flurl 的 AddHeader(s) 实现更改为使用 TryAddWithoutValidation

【讨论】:

  • 谢谢!对此非常满意,谢天谢地,我现在可以将 flurl 与需要 system.net.http 认为无效的标头的 Api 一起使用
【解决方案4】:
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; }
}

【讨论】:

    【解决方案5】:

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

    Upgrade.Flurl.Http 2.0 包括以下对标头的增强:

    1. WithHeader(s) 现在在后台使用TryAddWithoutValidation。仅通过该更改,OP 的代码将按照最初发布的方式运行。

    2. 现在在请求级别设置标头,这解决了another known issue

    3. SetHeaders 与对象表示法一起使用时,在标头名称中使用underscores in property names will be converted to hyphens,因为标头中的连字符很常见,下划线不是,C# 标识符中不允许使用连字符。

      李>

    这对你的情况很有用:

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

    【讨论】:

    • 嗨,托德,您能否从 2017 年 7 月 14 日开始添加提示/编辑您的答案。这里很容易错过。谢谢:-)
    • 我做到了。你错过了粗体部分吗? ;)
    猜你喜欢
    • 2018-05-20
    • 1970-01-01
    • 2010-10-31
    • 2021-04-12
    • 1970-01-01
    • 2015-07-14
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多