如何使用 HttpWebRequest GET 方法 w/ContentType=“application/json”

发布于 2024-10-11 04:27:17 字数 3035 浏览 6 评论 0原文

这个非常简单,运行这个 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(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔ignoreSyncCtx) 在 System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 在 System.Threading.ThreadPoolWorkQueue.Dispatch() 在 System.Threading.ThreadPoolWaitCallback.PerformWaitCallback() 内部异常:System.NotSupportedException 消息=不支持指定的方法。 堆栈跟踪: 在 System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult) 在 System.Net.Browser.BrowserHttpWebRequest.<>c_DisplayClass5.b_4(对象 sendState) 在 System.Net.Browser.AsyncHelper.<>c_DisplayClass2.b__0(Object sendState) InnerException:

正在工作

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

就是这样!

我知道每个人在想什么,这本来可以解决,我会包含其中一些细节..比如更改 URI 的调试标志,我删除了大部分代码以使其更易于阅读,我认为问题出在网络堆栈上。

感谢所有花时间参与其中的人,无论是在 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!");
        }
    });
}

This one is real simple, run this Silverlight4 example with the ContentType property commented out and you'll get back a response from from my service in xml. Now uncomment the property and run it and you'll get an ProtocolViolationException, what should happen is the service returns JSON formatted data.

#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);

New exception

System.NotSupportedException was unhandled by user code
Message=""
StackTrace:
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at com.patten.silverlight.ViewModels.WebRequestLiteViewModel.b_0(IAsyncResult cb)
at System.Net.Browser.BrowserHttpWebRequest.<>c
_DisplayClassd.b__b(Object state2)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.ThreadPoolWaitCallback.PerformWaitCallback()
InnerException: System.NotSupportedException
Message=Specified method is not supported.
StackTrace:
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c
_DisplayClass5.b_4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c
_DisplayClass2.b__0(Object sendState)
InnerException:

WORKING NOW

The exception that I was getting was due to a hack I use to get Fiddler to show the loop-back adapter i.e. http://localhost.:55437/Services/GetFoodDescriptionsLookup(2100), notice the extra DOT after the word localhost.

That was it!

I know what everyone is thinking, this could have been solved it I would have included some of these details.. like the debug flag that changes the URI, I removed most of the code to make it easier to read on SO, thinking that the problem was in the networking stack. Hard lesson(s) learned.

Thanks to everyone who took the time to get involved with this, both on stackoverflow and offline.

For completeness I have added the jQuery function that had me thinking this whole time I needed to be setting "content-type" instead of "accept" when in the SL4 application. (READ THE DOCS!)

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!");
        }
    });
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

春夜浅 2024-10-18 04:27:17

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

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

这是 帖子涵盖了从服务器端执行此操作的各种方法。如果您选择支持自动格式选择,则需要设置 接受 HttpWebRequest 标头到“application/json”

Stephen, setting the content type is to allow SENDING JSON, not receiving it. There are several ways to do this. You can support both JSON and XML or only JSON. If all you want to do is support JSON then you can do this by setting the ResponseFormat property on the WebGet attribute for the service operation.

If you want to support both JSON and XML then you need to either enable automatic format selection on the service and send an accept header of "application/json", otherwise you
can use a format string parameter in the query string and have the service use the WebOperationContext.OutgoingResponse.Format property.

Here's a post that covers various ways to do this from the server side. If you go the route of supporting automatic format selection then you need to set the accept header of the HttpWebRequest to "application/json"

哑剧 2024-10-18 04:27:17

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

If you finally determine that it's a problem in the Silverlight HttpWebRequest, i.e., it might have a bug or excessively stupid security check in it that keeps it from handling text/json responses, one reasonable (if annoying) workaround might be to shell out to javascript to make the request, using the XMLHttpRequest object, and then return the results to Silverlight. Annoying, but possible.

在风中等你 2024-10-18 04:27:17

格伦·布洛克的回答似乎已经说了这一点,但我想它还不够清楚。

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

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

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

让我们从头开始:您想要取回 JSON 数据。这是通过使用 Accept 标头来完成的,它告诉服务器您想要返回什么类型的数据。因此,将其替换

wreq.ContentType = "application/json"; 

为此

wreq.Accept = "application/json"; 

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

Glenn Block's answer already seems to say this but I guess it was not clear enough.

The Content-Type header tells what type of data is in a POST body or HTTP response body

Your HTTP request is not either of these. It is a GET request without any body. This is why you are getting a protocol violation exception - GET requests cannot have a Content-Type header because by definition they do not have any content.

Your Fiddler request is working simply because WCF is very accomodating to buggy clients. The error is coming from inside the Silverlight networking stack, which refuses to send a broken request.

Let's take it from the top: you want to get back JSON data. This is accomplished using the Accept header, which tells the server what kind of data you want to get back. Therefore, replace this

wreq.ContentType = "application/json"; 

with this

wreq.Accept = "application/json"; 

and you will get JSON data from the server.

魂归处 2024-10-18 04:27:17

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

Can you post the details for the WCF End point? If it is returning XAML, the only way to get JSON is if it is configured to. The initial request simply requests a URL, it is not specifying a "mode" so I'm assuming the WCF is defaulting to XML. There should either be a specific endpoint to go to for JSON responses, or a setting on the WCF to return those only.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文