协商媒体类型时,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 响应标头 的相关文章

  • 如何禁用 HTTP 的 HSTS 标头?

    我已将以下内容插入到我网站的 htaccess 中 以便能够访问HSTS预加载列表 https hstspreload appspot com
  • .net core 2.0代理请求总是导致http 407(需要代理身份验证)

    我正在尝试通过 net core 2 0 Web 应用程序中的 WebProxy 发出 HTTP 请求 我得到的代码在 net框架中运行良好 所以我知道 相信 这不是环境问题 我也尝试使用两者来发出请求HttpWebRequest and
  • 无法从 Windows 7 上的 Windows 服务启动桌面应用程序

    HI 我在 Windows 7 上有 C WCF Windows 服务 以具有管理员权限的用户身份登录 我正在尝试在服务启动后启动桌面应用程序 我发现的所有讨论都是关于 Windows 工作站和桌面 我创建了一个单独的线程 设置线程工作站和
  • 自定义 WCF DataContractSerializer

    是否可以用我自己的序列化程序替换 Windows Communication Foundation 中的 dataContractSerializer 如果可能的话 我怎样才能实现这一目标 是的 您可以提供自己的序列化器实现 默认情况下 W
  • jquery ajax“发布”调用

    我是 jQuery 和 Ajax 的新手 并且在 发布 方面遇到问题 我正在使用 jQuery Ajax post 调用将数据保存到数据库 当我尝试保存数据时 它将 null 传递给我的 C 方法 jQuery 看起来像这样 functio
  • 使用 ContractNamespace 属性设置 WCF DataContract 命名空间

    在设计我的服务时 我决定要自定义出现在生成的 WSDL 中的名称空间 对于数据合同 我遇到了合约命名空间 http msdn microsoft com en us library system runtime serialization
  • 从一个客户端使用多个 WCF 服务

    我的网络场有 10 台运行 IIS 的服务器 在每台服务器上我都有相同的网站和相同的 WCF 服务 它公开了一些用于读取 删除缓存 会话 应用程序变量和其他内部数据的功能 在其他一些 Web 服务器上 我有一个 管理 Web 应用程序 它是
  • ASP.NET 中 HTTP 缓存相关标头的有效含义

    我正在 ASP NET 2 0 中开发一个 Web 应用程序 其中涉及通过资源处理程序 ashx 提供图像 我刚刚实现了处理缓存标头和条件 GET 请求 这样我就不必为每个请求提供所有图像 但我不确定我是否完全理解浏览器缓存发生了什么 图像
  • python 2.7 中的 HTTP 2 请求

    在 python 中向 HTTP 1 和 HTTP 2 发出请求有什么区别吗 我可以像这样在 python 中进行 HTTP 1 x 调用 url http someURL values param1 key param2 key2 dat
  • $http.get() 与 JSON 数据

    我正在编写一个服务器应用程序 并希望客户端使用正文中的数据来参数化我的 GET 方法 如下所示 http v GET http localhost 3000 url text 123 foo bar GET url HTTP 1 1 Acc
  • 如何在flutter项目中使用http拦截器?

    我必须向我的所有 Api 添加标头 有人告诉我为此使用 http 拦截器 但我无法理解如何做到这一点 因为我是颤振的新手 谁能帮我举个例子吗 您可以使用http 拦截器 https pub dev packages http interce
  • 服务器响应中的“连接:保持活动状态”

    我正在尝试建立从 Silverlight 应用程序到 Apache 服务器托管的 PHP 页面的 HTTP 持久连接 即无需为每个 HTTP 请求创建新的 TCP 连接 为此 我需要网络服务器发送其 HTTP 响应 并将 Connectio
  • WCF 服务参考支持文件未更新

    我有一个 VS 2010 解决方案 其中包含一个 WCF 服务项目和一个单元测试项目 单元测试项目有一个对WCF服务的服务引用 WCF 服务项目的 Web config 将许多绑定属性设置为非默认值 网络配置 特别注意maxBufferSi
  • WCF 服务中的“即发即忘”

    我在 Azure 上有很多 WCF REST 服务 在某些 WCF 服务中 我向外部服务调用 Http 请求 例如发送电子邮件 短信 对非关键第三方服务的 http 请求 我不希望这阻碍我对客户电话的响应 需要一些关于在这种情况下使用的模式
  • 如何为本机启用现有 WCF 服务的 JSONP?

    我有一个现有的服务 如下方法 AspNetCompatibilityRequirements RequirementsMode AspNetCompatibilityRequirementsMode Allowed ServiceBehav
  • WCF 与 .Net 远程处理

    根据本文 http msdn microsoft com en us library bb310550 aspx 带有命名管道的WCF是IPC的最佳选择 它比 Net Remoting快25 左右 我有以下代码 将 WCF 与命名管道与 N
  • 使用 flash 或 java servlet 将麦克风数据从浏览器上传到服务器的教程? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 There was a question on how to get data from a microphone on a client
  • 为什么我的 Github 托管网站响应 HTTP 302 而不是 200?

    我拥有该域名penkov id au http penkov id au 我主持一个blog http michael penkov id au blog 2014 01 02 reinventing the wheel html usin
  • 如何将文件透明地传输到浏览器?

    受控环境 IE8 IIS 7 ColdFusion 当从 IE 发出指向媒体文件 例如 mp3 mpeg 等 的 GET 请求时 浏览器将启动关联的应用程序 Window Media Player 我猜测 IIS 提供文件的方式允许应用程序
  • 使用 file_get_content 发布数据

    我已经做了一些关于如何使用的研究file get content与帖子 我也读过this one https stackoverflow com questions 2445276 how to post data in php using

随机推荐

  • 按下主页按钮后如何在后台设置 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