协商媒体类型时,WCF REST 不返回 Vary 响应标头

2023-12-23

我有一个简单的 WCF REST 服务:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1
{
    [WebGet(UriTemplate = "{id}")]
    public SampleItem Get(string id)
    {
        return new SampleItem() { Id = Int32.Parse(id), StringValue = "Hello" };
    }
}

对于服务应该返回的媒体没有限制。

当我发送指定的请求时json格式,它返回 JSON:

GET http://localhost/RestService/4 HTTP/1.1
User-Agent: Fiddler
Accept: application/json
Host: localhost

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 30
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sun, 02 Oct 2011 18:06:47 GMT

{"Id":4,"StringValue":"Hello"}

当我指定xml,它返回 XML:

GET http://localhost/RestService/4 HTTP/1.1
User-Agent: Fiddler
Accept: application/xml
Host: localhost

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 194
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sun, 02 Oct 2011 18:06:35 GMT

<SampleItem xmlns="http://schemas.datacontract.org/2004/07/RestPrototype.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Id>4</Id><StringValue>Hello</StringValue></SampleItem>

到目前为止一切顺利,问题是该服务没有返回VaryHTTP 标头表明内容已协商完毕并且Accepthttp header 是一个决定因素。

不应该是这样吗?:

GET http://localhost/RestService/4 HTTP/1.1
User-Agent: Fiddler
Accept: application/json
Host: localhost

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 30
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Vary:Accept
Date: Sun, 02 Oct 2011 18:06:47 GMT

{"Id":4,"StringValue":"Hello"}

据我所知,就缓存而言,“Vary”标头将告诉中间缓存响应是根据 URI 和AcceptHTTP 标头。否则,代理可以缓存 json 响应,并将其用于请求 xml 的人。

有什么方法可以让 WCF REST 自动放置此标头吗?

Thanks.


您可以使用自定义消息检查器来添加Vary响应的标题。基于WCF WebHTTP 的自动格式化规则 http://msdn.microsoft.com/en-us/library/ee476510.aspx,顺序为1)Accept header; 2)请求消息的Content-Type; 3)操作中的默认设置和4)行为本身的默认设置。只有前两个依赖于请求(从而影响Varyheader),对于您的场景(缓存),只有 GET 感兴趣,因此我们也可以丢弃传入的 Content-Type。所以编写这样一个检查器相当简单:如果AutomaticFormatSelectionEnabled设置了属性,然后我们添加Vary: Accept所有 GET 请求的响应的标头 - 下面的代码就是这样做的。如果您想包含内容类型(也适用于非 GET 请求),您可以修改检查器以查看传入的请求。

public class Post_0acbfef2_16a3_440a_88d6_e0d7fcf90a8e
{
    [DataContract(Name = "Person", Namespace = "")]
    public class Person
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
    }
    [ServiceContract]
    public class MyContentNegoService
    {
        [WebGet(ResponseFormat = WebMessageFormat.Xml)]
        public Person ResponseFormatXml()
        {
            return new Person { Name = "John Doe", Age = 33 };
        }
        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        public Person ResponseFormatJson()
        {
            return new Person { Name = "John Doe", Age = 33 };
        }
        [WebGet]
        public Person ContentNegotiated()
        {
            return new Person { Name = "John Doe", Age = 33 };
        }
        [WebInvoke]
        public Person ContentNegotiatedPost(Person person)
        {
            return person;
        }
    }
    class MyVaryAddingInspector : IEndpointBehavior, IDispatchMessageInspector
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            WebHttpBehavior webBehavior = endpoint.Behaviors.Find<WebHttpBehavior>();
            if (webBehavior != null && webBehavior.AutomaticFormatSelectionEnabled)
            {
                endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
            }
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            HttpRequestMessageProperty prop;
            prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
            if (prop.Method == "GET")
            {
                // we shouldn't cache non-GET requests, so only returning this for such requests
                return "Accept";
            }

            return null;
        }

        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            string varyHeader = correlationState as string;
            if (varyHeader != null)
            {
                HttpResponseMessageProperty prop;
                prop = reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty;
                if (prop != null)
                {
                    prop.Headers[HttpResponseHeader.Vary] = varyHeader;
                }
            }
        }
    }
    public static void SendGetRequest(string uri, string acceptHeader)
    {
        SendRequest(uri, "GET", null, null, acceptHeader);
    }
    public static void SendRequest(string uri, string method, string contentType, string body, string acceptHeader)
    {
        Console.Write("{0} request to {1}", method, uri.Substring(uri.LastIndexOf('/')));
        if (contentType != null)
        {
            Console.Write(" with Content-Type:{0}", contentType);
        }

        if (acceptHeader == null)
        {
            Console.WriteLine(" (no Accept header)");
        }
        else
        {
            Console.WriteLine(" (with Accept: {0})", acceptHeader);
        }

        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
        req.Method = method;
        if (contentType != null)
        {
            req.ContentType = contentType;
            Stream reqStream = req.GetRequestStream();
            byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
            reqStream.Write(bodyBytes, 0, bodyBytes.Length);
            reqStream.Close();
        }

        if (acceptHeader != null)
        {
            req.Accept = acceptHeader;
        }

        HttpWebResponse resp;
        try
        {
            resp = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            resp = (HttpWebResponse)e.Response;
        }

        Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
        foreach (string headerName in resp.Headers.AllKeys)
        {
            Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
        }
        Console.WriteLine();
        Stream respStream = resp.GetResponseStream();
        Console.WriteLine(new StreamReader(respStream).ReadToEnd());

        Console.WriteLine();
        Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
        Console.WriteLine();
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(MyContentNegoService), new Uri(baseAddress));
        ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(MyContentNegoService), new WebHttpBinding(), "");
        endpoint.Behaviors.Add(new WebHttpBehavior { AutomaticFormatSelectionEnabled = true });
        endpoint.Behaviors.Add(new MyVaryAddingInspector());
        host.Open();
        Console.WriteLine("Host opened");

        foreach (string operation in new string[] { "ResponseFormatJson", "ResponseFormatXml", "ContentNegotiated" })
        {
            foreach (string acceptHeader in new string[] { null, "application/json", "text/xml", "text/json" })
            {
                SendGetRequest(baseAddress + "/" + operation, acceptHeader);
            }
        }

        Console.WriteLine("Sending some POST requests with content-nego (but no Vary in response)");
        string jsonBody = "{\"Name\":\"John Doe\",\"Age\":33}";
        SendRequest(baseAddress + "/ContentNegotiatedPost", "POST", "text/json", jsonBody, "text/xml");
        SendRequest(baseAddress + "/ContentNegotiatedPost", "POST", "text/json", jsonBody, "text/json");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协商媒体类型时,WCF REST 不返回 Vary 响应标头 的相关文章

  • DefaultHttpClient GET 和 POST 命令 Java Android

    好的 这是我的应用程序 一个 Android 应用程序 允许我从移动应用程序 而不是从网站 将 CokeZone 代码提交到 CokeZone co uk 所以我编写了这部分代码来执行登录后命令 然后检查我是否登录后 问题是 发送 post
  • 身份验证中的随机数使用

    在基于摘要的身份验证中 随机数由服务器生成 然而 在基于 OAuth 的身份验证中 随机数是由客户端生成的 我想知道是否有人知道差异的原因 随机数用于使请求唯一 在没有随机数的身份验证方案中 恶意客户端可以生成一次请求并重放多次 即使计算成
  • 如何通过 HTTP POST 发送充满对象的 NSArray?

    我在 iPhone 端有一个产品 购物清单 由具有名称 product id 等的产品对象组成 我希望将此列表发送到服务器 在那里我将服务器上的列表与 iphone 中的列表进行比较 以合并所做的更改并将合并的列表发送回 iphone 如何
  • 是否有管理 __utma、__utmz 等 cookie 的标准?

    无论我登录 Facebook 还是 Twitter 我都会受到以下名称的 cookie 轰炸 utma utmb utmc utmv 它们的功能是什么 是否有一个标准来管理这些在服务器端的使用方式 这些 cookie 通常与谷歌分析 htt
  • 如何使用独立的 Jetty 进行服务器推送

    我正在尝试使用独立的 Jetty 在静态网站上测试服务器推送功能 我的网站由一个index html 1个CSS 一堆图像组成 目录结构为 Album index html style css images image 1 png a se
  • HTTP 和 HTTPS iframe

    我正在创建一个小部件 我想允许其他人使用它 这iframe通过 HTTP 加载 但我想允许用户通过 HTTPS 登录 即通过 SSL 发送登录请求 同源策略中允许这样做吗 即 场景是用户可以将我的 JavaScript 集成到他们的网站 小
  • 工作组模式下 WCF MSMQ 的配置

    在尝试部署服务时 我发现它无法启动 因为 MSMQ 处于工作组模式 我创建了一个专用队列 并更改了配置文件以引用它 但 WCF 服务主机拒绝以以下消息启动 绑定验证失败 因为绑定的 MsmqAuthenticationMode 属性设置为
  • 通过 https 负载均衡器的 WCF http 服务

    我有一个可以通过 http 端点访问的 WCF Web 服务 现在 该服务应通过 https 与负载均衡器一起发布 客户端是通过 svcutil exe 在 Net 中创建的 但 Java 客户端也需要 WSDL 我的理解是 Web 服务在
  • HTTP部分上传、断点续传的标准方法

    我正在开发 http 客户端 服务器框架 并寻找处理部分上传的正确方法 与使用带有 Range 标头的 GET 方法进行下载相同 但是 HTTP PUT 并不打算恢复 据我所知 PATCH 方法不接受 Range 标头 有没有办法通过 HT
  • WCF 和 n 层架构以及序列化性能

    当使用 WCF 服务作为接口层使用 5 层架构 前端 gt 接口层 gt 业务层 gt 数据库层 gt 数据库 时 让客户端应用程序调用它的方法 我是否也应该使用 WCF 服务业务层和数据库层 我问是因为 3 个服务之间进行的所有序列化 反
  • Chrome 在传输一定量的数据后挂起 - 等待可用的套接字

    我有一个浏览器游戏 最近我开始向游戏添加音频 Chrome 无法加载整个页面并卡在 91 requests 8 1 MB transferred 并且不再加载任何内容 它甚至破坏了所有其他选项卡中的网站 说Waiting for avail
  • 错误:在 Visual Studio 2013 中找不到类型或命名空间名称“ApplicationUser”

    我正在学习 RESTful WCF 服务 教程 但是当我构建我的应用程序时 我收到此错误 找不到类型或命名空间名称 ApplicationUser 您是否缺少 using 指令或程序集引用 c users basma documents v
  • 外部依赖错误的 HTTP 状态代码

    当服务器与外部 API 通信出现问题时 返回的正确 HTTP 状态代码是什么 假设客户端向我的服务器 A 发送有效请求 然后 A 查询服务器 B 的 API 以便执行某些操作 然而 B 的 API 当前抛出 500 错误或因某种原因无法访问
  • 在处理程序之后访问 HTTP 请求上下文

    在我的日志记录中间件 链中的第一个 中 我需要访问一些在链下游的某些身份验证中间件中编写的上下文 并且仅在处理程序本身执行之后 旁注 需要首先调用日志记录中间件 因为我需要记录请求的持续时间 包括在中间件中花费的时间 此外 当权限不足时 身
  • 是否可以修改 $_SESSION 变量?

    恶意用户是否可以将 SESSION 在 php 中 变量设置为他想要的任何值 很大程度上取决于您的代码 有一点非常明显 SESSION username REQUEST username
  • Django 响应总是用 text/html 分块无法设置内容长度

    在我的Django应用程序的views py中 我在尝试设置以下HTTP标头字段后返回一个HttpResponse对象 Create a Response Object with the content to return response
  • 从 HTTP 登录到 HTTPS

    我的网站默认使用 HTTP 我确实有一个启用 HTTPS 的证书 但只有其上的某些区域强制建立安全连接 登录是通过 Ajax 处理的 我想开始使用 SSL 即使请求来自 HTTP 我尝试强制请求的地址具有 HTTPS 并且它完美地回复 然而
  • 有没有办法使用 ASP.NET 在用户离开页面时始终运行某些服务器端代码?

    我想知道当用户离开 ASP NET 中的页面时是否有任何方法可以始终运行一些服务器端代码 页面卸载事件不好 因为如果有人单击链接 则不会调用该事件 理想情况下 即使用户关闭浏览器 我也希望代码能够运行 我怀疑我所问的问题是不可能的 但问一下
  • 编写每个处理程序中间件

    我希望从处理程序中提取一些重复的逻辑 并将其放入一些每个处理程序的中间件中 特别是 CSRF 检查 检查现有会话值 即身份验证或预览页面 等 我读了关于此的几篇文章 http justinas org writing http middle
  • 如何从c#中的窗口服务获取登录用户和机器名?

    如何在c 中从窗口服务获取登录用户 交互式用户 和机器名 当我尝试使用环境和其他类来登录用户名时 它只从窗口服务返回 NT AUTHORITY SYSTEM 该服务在 SYSTEM 帐户下执行 因此您在Environment班级 机器名称应

随机推荐

  • 按下主页按钮后如何在后台设置 CABasicAnimation 动画?

    我是ios开发的新手 我在我的项目中使用轮子图像 动画在前景模式下工作正常 之后我按下主页按钮 现在我重新启动应用程序 滚轮动画不起作用 这是我的代码 CABasicAnimation animation CABasicAnimation
  • 模块中子应用程序之间的 Angular2 路由

    我正在将 Angular 2 1 用于一个大型应用程序 该应用程序具有多个子模块 每个子模块定义按功能组织的子应用程序 顶层模块通过导入每个子应用程序的路由等 为 RouterModule 配置整个应用程序的所有子路由 因此 从子应用程序的
  • 如何在 LINQ to Entities 查询中实现查询拦截? (C#)

    我正在尝试在 EF4 中实现加密列 并使用 CTP5 功能来允许简单地使用 POCO 来查询数据库 抱歉 这是很多话 但我希望下面的内容足以解释需求和问题 那么 一些背景知识以及我迄今为止的进展 目的是 如果您在不使用我们的 DAL 的情况
  • Scala 解析器组合器:在流中解析

    我在 scala 中使用本机解析器组合器库 我想用它来解析许多大文件 我已经设置了组合器 但是我尝试解析的文件太大 无法一次读入内存 我希望能够通过解析器从输入文件流式传输并将其读回磁盘 这样我就不需要一次将其全部存储在内存中 我当前的系统
  • 创建一个新的 SVGTransform 对象以附加到 SVGTransformList

    我正在使用 Firefox 3 6 想在单击时向 svg 元素添加翻译 该元素已经有其他翻译 var svgs document getElementsByTagName svg svg var group svgs 0 childNode
  • 未从 lambda 函数调用 aws ses.sendEmail

    我用 node js 编写的 lambda 函数非常简单 当 dynamo 数据库中出现新条目时 将调用 Lambda 然后我想循环遍历每个条目并发送电子邮件 由于某种原因 我无法理解为什么 ses SendEmail 函数从未被调用 我将
  • 如何将 PHP 中的数据插入到 MariaDB 中?

    我熟悉 MySql 数据库 但有一个名为 MariaDB 的新数据库 我尝试从 PHP 代码插入数据但不能 那么你能帮我插入数据吗 我的服务器上的 PHP 版本是 5 4 32 MySQL 版本是 10 0 20 MariaDB cll l
  • JavaScript 拆分如何处理阿拉伯语和英语数字字符串?

    当我尝试拆分时 8635 split 然后 JavaScript 给我这个结果 0 1 8635 console log 8635 split 当我尝试拆分时 2132 split 它给了我这个不同的结果 0 2132 1 console
  • 从三个不同的表创建一个表

    我在 SQL 中有三个表 我需要将它们全部合并为一个 我需要一张表中所有表的所有字段 所有表都包含来自三个不同年份的相同字段 我写了一段代码 CREATE TABLE COL TBL TRAINING ALL YEARS AS SELECT
  • 给定角度和线上的点绘制一条线

    在我的图像中 我有一个三角形 代表箭头 该箭头定义了在同一图像中进一步搜索所考虑的方向和区域 例如 如果我有一个相对 x 轴旋转 30 度的三角形 并且它的尖端位于图像中的 250 150 处 我想找到并画一条垂直于三角形尖端的线 如下图所
  • python lxml 树,line[] 创建多行,需要单行输出

    我正在使用 lxml 使用 python 创建一个 xml 文件 我正在逐行解析文件 查找字符串 如果该字符串存在 我将创建一个子元素 我正在为 SubElement 分配一个值 该值存在于解析文件中我正在搜索的字符串之后 问题 如何将所有
  • 将 Jquery Ajax 与 PHP 结合使用

    我有用 javascript ajax 编写的代码 我喜欢将相同的代码传输到 jquery 中 这是我的 javascript Ajax 代码 function cascadeCountry value if document getEle
  • 在适用于 Linux 的 Windows 子系统上运行 JavaFX 15 应用程序时出现内部错误

    当我尝试在适用于 Linux WSL2 Ubuntu 20 04 的 Windows 子系统上运行 JavaFX 15 应用程序时 我遇到了困难 需要有关后续尝试步骤的建议 到目前为止 我已经能够在 WSL 内运行我通常在 Windows
  • 卸载并重新安装节点

    我正在我的 MacBook 上卸载并重新安装 Node 和 npm 到目前为止我已经做了 sudo rm rf usr local lib node modules npm 酿造卸载节点 酿造取消链接节点 sudo rm rf 任何和所有节
  • OSGi 和 Akka 如何互相受益?这是如何构造的?

    跟进我的相当不合逻辑的问题 https stackoverflow com questions 20122538 component based application with scalability in mind osgi or ak
  • .Net Core 中的 C++/CLI 支持

    我们的项目结构是这样的 native dll 这包含用 c c 编写的纯本机代码 这个native dll使用 def文件公开一些函数 Wrapper Library wrapper dll compiled with Net framew
  • 其他 HTTP 方法是否可以接受 HTTP 303?

    RESTful Web 服务 http shop oreilly com product 9780596529260 do鼓励使用HTTP 303 http www w3 org Protocols rfc2616 rfc2616 sec1
  • 如何使用媒体查询将手机上的 3 列 CSS 网格更改为 1 列

    我正在使用 CSS 网格在大屏幕上将文本与图片混合 不过 我希望他们在手机上形成一个专栏 基本上 桌面设备上有 3 列 移动设备上有 1 列 如何使用媒体查询实现这一点 我正在考虑寻找网格命令以在以下情况下禁用768px但甚至不知道这样的事
  • 保持两个 mySQL 数据库(位于不同位置)同步的策略? [复制]

    这个问题在这里已经有答案了 可能的重复 使用mysql双向实时同步动态数据最好的方法是什么 https stackoverflow com questions 325791 which is the best way to bi direc
  • 协商媒体类型时,WCF REST 不返回 Vary 响应标头

    我有一个简单的 WCF REST 服务 ServiceContract AspNetCompatibilityRequirements RequirementsMode AspNetCompatibilityRequirementsMode