使用 gzip 编码时,WCF 服务返回不正确的内容长度
我有一个包含过滤文本框和列表框的网页。对文本框的修改会触发 AJAX 请求,该请求返回一个值数组,用于填充列表框。
我遇到了这些调用有时失败的问题,具体取决于返回数据的大小。返回数据量小会出错,数据量大则返回并处理成功。
仅当我使用高于 4.2 的 jQuery 版本时才会出现此问题。如果我使用 jQuery 4.2 版本,就不会出现这个问题。
Here is the code of the call:
jQuery.ajax(
{
cache: false,
url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
type: "GET",
complete: function (jqXHR, textStatus) {
var responseText = jqXHR.responseText;
jQuery('#debugConsole').text(responseText);
availableVideosPopulationState.isRunning = false;
setTimeout(populateAvailableVideosListBox, 100);
},
data: { "companyIdString": queryParameters.companyIdField,
"textFilter": queryParameters.filterText
},
dataType: 'json',
error: function (jqXHR, textStatus, errorThrown) {
var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
alert(errorString);
},
success: function (data, textStatus, jqXHR) {
populateVideoListFromAjaxResults(data);
}
}
);
如果返回两个元素,则调试控制台的内容如下:
{"d":[{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1.mpg - [SOJACKACT0310DSN1]","Value":"5565_5565"},{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1Q.mpg - [SOJACKACT0310DSN1Q]","Value":"5566_5566"}]}
但如果返回一个元素:
{"d":[{"__type":"
那么,当然,我们会收到“未终止的字符串常量”错误。
我使用 fiddler 做了一些调查。
对于所有响应(甚至是成功的响应),fiddler 显示错误:
Fiddler 在会话 #n1 中检测到协议违规。
内容长度不匹配:响应标头指示 n2 字节,但是 服务器发送了n3个字节。
如果响应标头指示的大小大于实际大小,则浏览器仍可以解释结果。
如果响应标头指示的大小小于实际大小,则浏览器无法解释结果。
明显的假设是响应处理代码读取 Content-Length
标头,并且不会读取超过长度中规定的数据。
我调查的下一步是比较 jQuery 版本 1.6.1(损坏)和版本 1.4.2(未损坏)的请求/响应标头。
jQuery 1.6.1 请求标头:
GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?companyIdString=2&textFilter=3DSBDL2&_=1315869366142 HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6
jQuery 1.6.1 响应标头
<前><代码>HTTP/1.1 200 好的 服务器:ASP.NET开发服务器/10.0.0.0 日期:2011 年 9 月 12 日星期一 23:02:36 GMT X-AspNet-版本:4.0.30319 内容编码:gzip 内容长度:140 缓存控制:私有 内容类型:application/json;字符集=utf-8 连接:关闭
这是我使用 jQuery 1.4.1 时的请求标头。请注意,Accept
标头与 jQuery 1.6.1 值不同。
GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?_=1315870305531&companyIdString=2&textFilter=3DSBDL2 HTTP/1.1
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6
返回 jQuery 4.1.1 的响应:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 12 Sep 2011 23:31:46 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 131
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close
所以明显的区别是,当通过 jQuery 1.6.1 进行调用时,响应会使用 gzip 进行压缩,而当通过 jQuery 1.4.2 进行调用时,响应不会被压缩。
So now I can do a work around solution, which is to override the default Accept header to ensure it does not contain the
"q=0.01"
string. (The best explanation I can find for "q=0.01"
is here, but I fail to see why my service implementation is interpreting this as a request to zip up the response badly.) // Make the AJAX call, passing in the company id and the filter string
jQuery.ajax(
{
accepts: 'application/json, text/javascript, */*',
cache: false,
url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
type: "GET",
complete: function (jqXHR, textStatus) {
var responseText = jqXHR.responseText;
jQuery('#debugConsole').text(responseText);
availableVideosPopulationState.isRunning = false;
setTimeout(populateAvailableVideosListBox, 100);
},
data: { "companyIdString": queryParameters.companyIdField,
"textFilter": queryParameters.filterText
},
dataType: 'json',
error: function (jqXHR, textStatus, errorThrown) {
var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
alert(errorString);
},
success: function (data, textStatus, jqXHR) {
populateVideoListFromAjaxResults(data);
}
}
);
因此,在完成所有这些调查之后,剩下的问题是,当响应经过 GZIP 压缩时,为什么内容长度标头与实际内容长度之间存在差异?
我正在使用带有 webHttpBinding 的 WCF 服务。
I have a web page containing a filtering text box and a list box. Modifications to the text box trigger an AJAX request, which returns an array of values with which to populate the list box.
I had problems with these calls failing sometimes, dependent on the size of the data returned. Small-sized returned data would result in an error, large-size data was returned and processed succesfully.
This problem only happens when I use a jQuery version greater than 4.2. If I use jQuery version 4.2, I don't have the problem.
Here is the code of the call:
jQuery.ajax(
{
cache: false,
url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
type: "GET",
complete: function (jqXHR, textStatus) {
var responseText = jqXHR.responseText;
jQuery('#debugConsole').text(responseText);
availableVideosPopulationState.isRunning = false;
setTimeout(populateAvailableVideosListBox, 100);
},
data: { "companyIdString": queryParameters.companyIdField,
"textFilter": queryParameters.filterText
},
dataType: 'json',
error: function (jqXHR, textStatus, errorThrown) {
var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
alert(errorString);
},
success: function (data, textStatus, jqXHR) {
populateVideoListFromAjaxResults(data);
}
}
);
Here is the contents of the debug console if two elements are returned:
{"d":[{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1.mpg - [SOJACKACT0310DSN1]","Value":"5565_5565"},{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1Q.mpg - [SOJACKACT0310DSN1Q]","Value":"5566_5566"}]}
But if one element is returned:
{"d":[{"__type":"
So, of course, we get an "Unterminated String Constant" error.
I have done some investigation using fiddler.
On all responses (even the succesful ones), fiddler displayed an error:
Fiddler has detected a protocol violation in session #n1.
Content-Length mismatch: Response Header indicated n2 bytes, but
server sent n3 bytes.
If the response header indicates a size greater than than actual size, then the results could still be interpreted by the browser.
If the response header indicates a size less than the actual size, then the browser could not interpret the results.
The obvious assumption to make there is that the response handling code reads the Content-Length
header and doesn't read any more data than that stipulated in the length.
The next step in my investigation is to compare the request/response headers for jQuery version 1.6.1 (which breaks) and version 1.4.2 (which does not break).
jQuery 1.6.1 request header:
GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?companyIdString=2&textFilter=3DSBDL2&_=1315869366142 HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6
jQuery 1.6.1 response headers
HTTP/1.1 200 OK Server: ASP.NET Development Server/10.0.0.0 Date: Mon, 12 Sep 2011 23:02:36 GMT X-AspNet-Version: 4.0.30319 Content-Encoding: gzip Content-Length: 140 Cache-Control: private Content-Type: application/json; charset=utf-8 Connection: Close
And here is the request header when I use jQuery 1.4.1. Notice that the Accept
header is different from the jQuery 1.6.1 value.
GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?_=1315870305531&companyIdString=2&textFilter=3DSBDL2 HTTP/1.1
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6
And the response back to jQuery 4.1.1:
HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 12 Sep 2011 23:31:46 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 131
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close
So the obvious difference is that when the call is made via jQuery 1.6.1 the response is compressed using gzip, and when the call is made via jQuery 1.4.2 the response is not compressed.
So now I can do a work around solution, which is to override the default Accept header to ensure it does not contain the
"q=0.01"
string. (The best explanation I can find for "q=0.01"
is here, but I fail to see why my service implementation is interpreting this as a request to zip up the response badly.) // Make the AJAX call, passing in the company id and the filter string
jQuery.ajax(
{
accepts: 'application/json, text/javascript, */*',
cache: false,
url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
type: "GET",
complete: function (jqXHR, textStatus) {
var responseText = jqXHR.responseText;
jQuery('#debugConsole').text(responseText);
availableVideosPopulationState.isRunning = false;
setTimeout(populateAvailableVideosListBox, 100);
},
data: { "companyIdString": queryParameters.companyIdField,
"textFilter": queryParameters.filterText
},
dataType: 'json',
error: function (jqXHR, textStatus, errorThrown) {
var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
alert(errorString);
},
success: function (data, textStatus, jqXHR) {
populateVideoListFromAjaxResults(data);
}
}
);
So after all this investigation, the remaining question is why is there a disparity between the content length header and the actual content length when the response is GZIP compressed?
I'm using a WCF service with webHttpBinding.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先——非常好的问题。这个问题为我提供了足够的信息来解决我的问题。
我遇到了类似的问题,并在这里发布了修复程序 - 这样它可能会对某人有所帮助。
Ajax 获取& POST 请求在 IE 中返回 null
在其他浏览器中工作正常,但在 fiddler 中看到“响应标头指示 n 个字节,但服务器发送了 nn 个字节”消息。
我也这么认为!
在这种情况下,我很清楚一件事。 某些内容篡改了请求/响应。
我尝试切换回旧版本的 jQuery(如您的问题中提到的),但这没有帮助。
修复-
我打开了应用程序的网络配置,并仔细阅读了它。
模块中包含来自 telerik 的'RadCompression Module',删除它后一切都开始正常工作。
已知 RadCompression 模块存在错误,并会通过压缩响应而导致多个问题。
如果您遇到类似问题,请尝试检查可能拦截您的请求/响应的内容。
First of all-Very good question. This question provided me with enough information to reach a solution for my problem.
I had a similar issue, and posting the fix here- so that it might help someone.
Ajax get & post requests were returning null in IE
Was working fine in rest of the browsers, but saw the 'Response Header indicated n bytes, but server sent nn bytes' message in fiddler for the request.
I think so too!
In this case, I was clear with one thing. Something was tampering the request/response.
I tried switching back to older version of jQuery (as mentioned in your question), but that didn't help.
Fix-
I opened up the web config of my application, and read through it.
There was a 'RadCompression Module' from telerik included in modules, and on removal of it everything started working fine.
RadCompression module is known to be buggy and cause multiple issues by compressing the Response.
If you are having similar issues, try checking what might be intercepting your request/response.
响应标头指示 140 字节,但服务器发送了 254 字节
说明了很多。无论您使用什么浏览器,都会发生同样的情况吗?如果是这样,我们可以说 IE 或 jQuery 1.4.3 以及 IE 中的更高版本在读取响应标头中指定的字节数后不会读取字节,而其他浏览器无论如何都会读取所有内容。也有可能(但我几乎不相信这一点)仅针对 IE 请求响应标头的格式错误。那么你必须看看IE和其他浏览器请求和你的服务代码的区别。也许您的服务专门处理 IE 请求?
计算 JSON 字符串中最后捕获的引号 (
"
) 之后有多少字节会很有趣。也许是 114?Response Header indicated 140 bytes, but server sent 254 bytes
says much. Does the same happen independently of the browser you use? If so, we may say that IE or jQuery 1.4.3 and further in IE does not read bytes after reading as many bytes as specified in Response Header, while other browsers read all the content anyway.It is also possible (yet I hardly believe this) that response header is wrongly formed only for IE requests. Then you must look at the differences between IE and other browser requests and your service code. Maybe your services handles IE requests specifically?
It would be interesting to calculate how much bytes there is after the last captured quotation mark (
"
) in your JSON string. 114 maybe?