breezejs inlineCount无法正常工作(CORS跨域http请求)

时间:2013-04-18 09:18:02

标签: jquery odata breeze

这是我的疑问:

 var query = breeze.EntityQuery
                .from("Mandates").skip(offset).take(pageSize).inlineCount(true);

        return manager.executeQuery(query);

在响应标头中,我可以看到服务器返回计数:

X-InlineCount:63

然而,在我做的成功处理程序中:

 var results = data.results;
 var recordCount = data.inlineCount;

结果包含正确的记录。但是data.inlineCount为null。

为什么?

修改

getAllResponseHeaders不会返回所有标头!我刚刚注意到他们中的大多数都丢失了,包括X-InlineCount。

我相信这是因为我正在进行跨域http请求(网站在localhost中,但我的webapi(Web服务)在域上的服务器上)。怎么解决这个问题?

2 个答案:

答案 0 :(得分:3)

我们已经确认了这个问题。我们计划通过将inlineCount移出标题并进入结果有效负载来修复它,它可能应该放在第一位。没有确定的日期,但很快。

  

更新:2013年4月18日。我们已在内部实现此修复程序,它通过了我们的测试。我们将在下一个NuGet(1.3.0之后的那个)中部署。当发生这种情况时,我会再次更新这个答案。

通过调整this jsFiddle,我们可以像任何人一样重现这个问题。

小提琴向Breeze服务器发出请求,公开Todos。当然,Breeze服务器与jsFiddle位于不同的域中,因此需要CORS来执行查询和保存操作。

我将getAllTodos方法更改为以下内容:

function getAllTodos() {
    var query = breeze.EntityQuery.from("Todos")

    // added for Cross-Origin inlineCount header testing
    .orderBy('Description')
    .skip(1).take(3)
    .inlineCount(true);

    log("Getting Todos");
    return manager.executeQuery(query)
    .then(querySucceeded).fail(failed);

    function querySucceeded(data) {
        var count = data.results.length;
        log("Retrieved " + count);

        // added for Cross-Origin inlineCount header testing
        log("Inline count: "+ data.inlineCount);
        log("Headers: " + data.XHR.getAllResponseHeaders());

        if (!count) {
            log("No Todos"); return;
        }
        viewModel.items(data.results);
    }
}

@jvrdelafuente - 我很惊讶您推荐的Web.config更改确实有效。我曾经认为对Web.config进行这样的更改只会影响服务器的功能,而不会影响浏览器的功能。

当我检查网络流量时,我可以看到服务器正在发送“X-InlineCount”标头,有或没有您建议的更改。浏览器(至少IE10和Chrome)似乎隐藏了jQuery.AJAX的标题,jQuery.AJAX负责典型的微风应用程序中的AJAX通信。

当我将以下内容添加到查询成功回调中时,我看到了这种效果:

 console.log("Headers: " + data.XHR.getAllResponseHeaders());

日志显示服务器实际返回的标头很少。

也许当你添加

<add name="Access-Control-Expose-Headers" value="X-InlineCount" />

到Web.config,服务器可以告诉浏览器将“X-InlineCount”标头暴露给JavaScript客户端是可以的。

我承认我没有调查这种可能性;也许这是短期内可行的解决方案。

但就我们而言,它只是一个乐队助手。我们不希望开发人员担心这种事情; CORS创造了足够的头痛。因此,我们将在有效负载而不是标题中传达inlineCount ...并一起消除这一问题。

答案 1 :(得分:1)

我遇到了同样的问题。您必须配置服务器以公开X-InlineCount标头。如果您使用的是项目ASP .NET Web API,则必须在web.config中添加下一行:

  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
        <add name="Access-Control-Allow-Methods" value="GET,POST,OPTIONS" />
        <add name="Access-Control-Expose-Headers" value="X-InlineCount" />
      </customHeaders>
    </httpProtocol>

另外,我遇​​到了firefox的问题,但是在最后一个版本的firefox中,问题就解决了。

(哟不需要使用所有的行,这只是一个例子);)

- - - - - - - - 编辑

我忘记了,因为这是日志时间之前。当您进行CORS呼叫时,浏览器首先发送一个Option调用,以检查是否可以进行CORS呼叫以及允许进行哪些操作。因此,您必须在WEB API项目中实现消息处理程序以管理此OPTION调用。实施是下一个:

public class OptionsHttpMessageHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request.Method == HttpMethod.Options)
            {
                var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer();


                var controllerRequested = request.GetRouteData().Values["controller"] as string;
                var supportedMethods =  apiExplorer.ApiDescriptions
                    .Where(d =>
                    {

                        var controller = d.ActionDescriptor.ControllerDescriptor.ControllerName;
                        return string.Equals(
                            controller, controllerRequested, StringComparison.OrdinalIgnoreCase);
                    })
                    .Select(d => d.HttpMethod.Method)
                    .Distinct();

                if (!supportedMethods.Any())
                    return Task.Factory.StartNew(
                        () => request.CreateResponse(HttpStatusCode.NotFound));

                return Task.Factory.StartNew(() =>
                {
                    var resp = new HttpResponseMessage(HttpStatusCode.OK);
                    resp.Headers.Add("Access-Control-Allow-Origin", "*");
                    resp.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept, Security,Token-Access");
                    resp.Headers.Add("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
                    resp.Headers.Add("Access-Control-Expose-Headers", "X-InlineCount");

                    return resp;
                });
            }

            return base.SendAsync(request, cancellationToken);
        }
    }

如果将其放在web.config中,可以省略下一节。

resp.Headers.Add("Access-Control-Allow-Origin", "*");
resp.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept, Security,Token-Access");
resp.Headers.Add("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
resp.Headers.Add("Access-Control-Expose-Headers", "X-InlineCount");

我希望这有助于解决您的问题。

PD:对不起我的英语,这不是我的第一语言。