【问题标题】:How do I use HttpWebRequest GET method w/ ContentType="application/json"如何使用带有 ContentType="application/json" 的 HttpWebRequest GET 方法
【发布时间】:2011-01-10 05:59:50
【问题描述】:

这个真的很简单,运行这个 Silverlight4 示例并注释掉 ContentType 属性,您将从我的服务以 xml 形式返回响应。现在取消注释该属性并运行它,您将得到一个 ProtocolViolationException,应该发生的是服务返回 JSON 格式的数据。

#if DEBUG
                Address = "http://localhost.:55437/Services/GetFoodDescriptionsLookup(2100)";
#else
                Address = "http://stephenpattenconsulting.com/Services/GetFoodDescriptionsLookup(2100)";
#endif

Uri httpSite = new Uri(Address);

HttpWebRequest wreq = 
(HttpWebRequest)WebRequestCreator.ClientHttp.Create(httpSite);

//wreq.ContentType = "application/json"; // Wrong
wreq.Accept = "application/json"; // Right

wreq.BeginGetResponse((cb) =>
{
    HttpWebRequest rq = cb.AsyncState as HttpWebRequest;
    HttpWebResponse resp = rq.EndGetResponse(cb) as HttpWebResponse; // Exception
    StreamReader rdr = new StreamReader(resp.GetResponseStream());
    string result =  rdr.ReadToEnd(); 
    rdr.Close();
}, wreq);

新异常

System.NotSupportedException 未被用户代码处理 消息="" 堆栈跟踪: 在 System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod,对象状态) 在 System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult) 在 com.patten.silverlight.ViewModels.WebRequestLiteViewModel.b_0(IAsyncResult cb) 在 System.Net.Browser.BrowserHttpWebRequest.c_DisplayClassd.b__b(Object state2) 在 System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(对象状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔 ignoreSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading.ThreadPoolWaitCallback.PerformWaitCallback() 内部异常:System.NotSupportedException Message=不支持指定的方法。 堆栈跟踪: 在 System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult) 在 System.Net.Browser.BrowserHttpWebRequest.c_DisplayClass5.b_4(Object sendState) 在 System.Net.Browser.AsyncHelper.c_DisplayClass2.b__0(对象 sendState) 内部异常:

现在工作

我得到的异常是由于我用来让 Fiddler 显示环回适配器的 hack,即 http://localhost.:55437/Services/GetFoodDescriptionsLookup(2100),请注意单词 localhost 后面的额外点。

就是这样!

我知道每个人都在想什么,这本来可以解决的认为问题出在网络堆栈中。艰难的教训。

感谢所有花时间参与此项目的人,无论是在 stackoverflow 上还是在离线状态。

为了完整起见,我添加了 jQuery 函数,这让我一直认为我需要在 SL4 应用程序中设置“内容类型”而不是“接受”。 (阅读文档!)

function CallService(serviceUrl, data, callback) {
    $.ajax({
        url: serviceUrl,
        data: data,
        dataType: 'json',
        contextType: "application/json", 
        cache: false,
        success: callback,
        error: function (msg) {
            alert("Request Failed!");
        }
    });
}

【问题讨论】:

  • 请发布来自 Fiddler 的请求和响应标头;另外,究竟是什么异常?我的意思是,消息和内部异常是什么。
  • 您编辑中的新异常是否与您在上面发布的代码完全相同?因为我试过了,它没有任何问题,所以我很惊讶。发生这种情况时,您能否发布您的 Silverlight 应用程序调用的 Fiddler 日志? (即不是在 Fiddler 中创建的手动请求)。如果您跨域使用此 Web 服务(因为不存在策略文件),该位置会出现异常,但您发布的异常不会出现,所以我认为这不是问题;只是为了确定-您的客户端应用程序也在同一个域上吗? (stephenpattenconsulting.com)
  • 是的,创建HttpWebResponse时抛出异常。

标签: silverlight wcf json httpwebrequest


【解决方案1】:

Stephen,设置内容类型是允许发送 JSON,而不是接收它。有几种方法可以做到这一点。您可以同时支持 JSON 和 XML 或仅支持 JSON。如果您只想支持 JSON,那么您可以通过在服务操作的 WebGet 属性上设置 ResponseFormat 属性来实现。

如果您想同时支持 JSON 和 XML,那么您需要在服务上启用自动格式选择并发送“application/json”的接受标头,否则您 可以在查询字符串中使用格式字符串参数并让服务使用 WebOperationContext.OutgoingResponse.Format 属性。

这是一个post,涵盖了从服务器端执行此操作的各种方法。如果你走的是支持自动格式选择的路线,那么你需要将HttpWebRequest的accept头设置为“application/json”

【讨论】:

  • 我也在帖子中添加了异常详情。
【解决方案2】:

如果您最终确定这是 Silverlight HttpWebRequest 中的问题,即它可能存在错误或过于愚蠢的安全检查,使其无法处理文本/json 响应,那么一种合理(如果烦人)的解决方法可能是使用 XMLHttpRequest 对象向 javascript 发出请求,然后将结果返回给 Silverlight。烦人,但可能。

【讨论】:

  • 出于好奇,您是否尝试过指定客户端(而不是浏览器)HTTP 处理?见这里:msdn.microsoft.com/en-us/library/dd920295(VS.95).aspx。我知道这两种方法的工作方式存在一些显着差异,可以想象这可能是其中之一。只是一个偶然的想法。
  • Ken,我也会错过它,但是如果您查看第一行代码,您可能会注意到与普通 WebRequest 工厂不同的东西,这是正在实例化的客户端(OS)网络堆栈通过 WebRequestCreator.ClientHttp.Create。好主意,但行不通。
  • 啊,好点子。好吧,问一个显而易见的问题,您是否尝试过另一种方式,使用浏览器 HTTP 堆栈?
【解决方案3】:

Glenn Block 的回答似乎已经说明了这一点,但我想这还不够清楚。

Content-Type 标头告诉 POST 正文或 HTTP 响应正文中的数据类型

您的 HTTP 请求不是其中任何一个。这是一个没有任何正文的 GET 请求。这就是您收到协议违规异常的原因 - GET 请求不能有 Content-Type 标头,因为根据定义,它们没有任何内容。

您的 Fiddler 请求之所以有效,仅仅是因为 WCF 非常适合有问题的客户端。该错误来自 Silverlight 网络堆栈内部,该堆栈拒绝发送损坏的请求。

让我们从头开始:您想要取回 JSON 数据。这是使用 Accept 标头完成的,该标头告诉服务器您想要取回什么样的数据。因此,替换这个

wreq.ContentType = "application/json"; 

有了这个

wreq.Accept = "application/json"; 

您将从服务器获取 JSON 数据。

【讨论】:

  • Sander,如果它没有导致我们已经离线的另一个问题,我会接受他的回答。稍后我会用我们的发现来清理这个问题。谢谢。
  • Sander 是正确的,只要服务器支持内容协商。在 WCF 中,如果您在绑定上设置 AutomaticFormattingEnabled 开关,就会发生这种情况。
  • 是的,自动格式化已打开,这就是为什么我一心想将接受标头更改为 application/json。仅供参考,现在我已经通过了协议例外,我正在获得一个新的,将其发布在上面。
【解决方案4】:

您能否发布 WCF 端点的详细信息?如果它返回 XAML,则获取 JSON 的唯一方法是配置为。初始请求只是请求一个 URL,它没有指定“模式”,所以我假设 WCF 默认为 XML。应该有一个特定的端点来获取 JSON 响应,或者 WCF 上的设置只返回那些。

【讨论】:

  • 更改内容类型足以让端点区分返回什么格式。默认为 GET XML,但如果您发出内容类型为 application/json 的 GET,则 wcf 将返回 json 格式的数据。这是运行时自动生成的帮助页面链接stephenpattenconsulting.com/Services/help/operations/…
  • 我应该澄清一下这个杰里米。我首先从一个使用 jQuery 访问服务的客户端网页开始这个练习。我设置这个调用的方式是什么让我坚持内容类型是需要设置的,以便自动格式化启动并返回 json。你知道你要为此负责,不是吗。 :)
猜你喜欢
  • 2014-04-27
  • 2011-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
  • 2018-01-24
  • 2013-12-16
相关资源
最近更新 更多