捆绑API请求 [英] Bundling API requests

查看:138
本文介绍了捆绑API请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建一个REST API,我一直在玩允许客户端请求的捆绑销售的想法。通过捆绑我的意思是,他们可以发送一个请求,包含多个真正的请求,他们得到交付客户在一起。通常JavaScript的Ajax请求。事情是这样的:

I am creating a REST API and I have been playing with the idea of allowing bundling of requests from clients. By bundling I mean they can send one request, containing multiple "real" requests, and they get delivered to the client together. Typically javascript ajax requests. Something like this:

POST /bundlerequest

["/person/3243", "/person/3243/friends", "/comments/3243?pagesize=10&page=1", "/products", "/product/categories" ] 

(捆绑的要求只能是GET请求,截至目前至少)
这是为了恢复像这样

(The bundled request can only be GET requests, as of now at least) This is intended to return something like this

{
    "success" : ["/person/3243", "/person/3243/friends", "/comments/3243?pagesize=10&page=1", "/products", "/product/categories" ],
    "error" : [],
    "completiontime" : 94,
    other relevant metadata...
    "responses" : [
        {"key" : "/person/3243" , "data" : {"name" : "John", ...} },
        {"key" : "/person/3243/friends" , "data" : [{"name": "Peter", "commonfriends" : 5, ...}] },
        etc...
    ]
}

此捆绑的好处是,它减少请求的数目,这是在例如移动设备尤其重要。

The benefits of this bundling is that it reduces the number of requests and that is especially important on mobile devices for instance.

所以我的第一个问题是,是我的方法,这是一个很好吗?有没有人有经验,做这样的事情?

AFAIK解决这一常见的方法是写服务器侧code返回组合的数据,我认为是相关的客户端(多个)。 (例如Twitter的用户流做到这一点,结合人的信息,最新的鸣叫,最新的个人消息等),但是这使得API非常刚愎自用,当客户需要改变服务器可能需要改变,以适应优化。

AFAIK the common way of solving this is to write server side code to return combined data, that I believe is relevant for the client(s). (The twitter user stream for instance does this, combining person info, latest tweets, latest personal messages etc.) But this makes the API very opinionated and when the client needs changes the server might need to change to accomodate to optimize.

而第二个问题是如何实现这一点?

我的后端是ASP.NET MVC 3和IIS 7.我应该落实在应用程序中,有一个bundlerequest动作在内部调用请求中指定的其他行动?

My backend is ASP.NET MVC 3 and IIS 7. Should I implement it in the application, having an bundlerequest action that internally calls the other actions specified in the request?

难道直接IIS 7中实现?编写透明截取请求/ bundlerequest,然后调用所有相应的子请求,使得应用程序完全不知道发生了捆绑的模块?这也让我在一个应用程序无关的方式实现这一点。

Could it be implemented in IIS 7 directly? Writing a module that transparently intercepts requests to /bundlerequest and then calls all the corresponding sub requests, making the application totally unaware of the bundling that happens? This would also allow me to implement this in an application-agnostic way.

推荐答案

您可以使用一个的异步控制器聚集在服务器上的这些请求。让我们先开始通过定义将被控制器返回的视图模型:

You could use an asynchronous controller to aggregate those requests on the server. Let's first start by defining a view model that will be returned by the controller:

public class BundleRequest
{
    public string[] Urls { get; set; }
}

public class BundleResponse
{
    public IList<string> Success { get; set; }
    public IList<string> Error { get; set; }
    public IList<Response> Responses { get; set; }
}

public class Response
{
    public string Key { get; set; }
    public object Data { get; set; }
}

则控制器:

public class BundleController : AsyncController
{
    public void IndexAsync(BundleRequest request)
    {
        AsyncManager.OutstandingOperations.Increment();
        var tasks = request.Urls.Select(url =>
        {
            var r = WebRequest.Create(url);
            return Task.Factory.FromAsync<WebResponse>(r.BeginGetResponse, r.EndGetResponse, url);
        }).ToArray();

        Task.Factory.ContinueWhenAll(tasks, completedTasks =>
        {
            var bundleResponse = new BundleResponse
            {
                Success = new List<string>(),
                Error = new List<string>(),
                Responses = new List<Response>()
            };
            foreach (var task in completedTasks)
            {
                var url = task.AsyncState as string;
                if (task.Exception == null)
                {
                    using (var response = task.Result)
                    using (var stream = response.GetResponseStream())
                    using (var reader = new StreamReader(stream))
                    {
                        bundleResponse.Success.Add(url);
                        bundleResponse.Responses.Add(new Response
                        {
                            Key = url,
                            Data = new JavaScriptSerializer().DeserializeObject(reader.ReadToEnd())
                        });
                    }
                }
                else
                {
                    bundleResponse.Error.Add(url);
                }
            }
            AsyncManager.Parameters["response"] = bundleResponse;
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ActionResult IndexCompleted(BundleResponse response)
    {
        return Json(response, JsonRequestBehavior.AllowGet);
    }
}

现在我们可以调用它:

and now we can invoke it:

var urls = [ 
    '@Url.Action("index", "person", new { id = 3243 }, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("friends", "person", new { id = 3243 }, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("index", "comments", new { id = 3243, pagesize = 10, page = 1 }, Request.Url.Scheme, Request.Url.Host)',
    '@Url.Action("index", "products", null, Request.Url.Scheme, Request.Url.Host)', 
    '@Url.Action("categories", "product", null, Request.Url.Scheme, Request.Url.Host)' 
];
$.ajax({
    url: '@Url.Action("Index", "Bundle")',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(urls),
    success: function(bundleResponse) {
        // TODO: do something with the response
    }
});

当然,一些调整可能需要这个适应您的特定需求。比如你提到发送带有会议AJAX请求过期可能会重定向到登录页面,因此不会捕捉错误。这确实是一个ASP.NET PITA。菲尔哈克<一个href=\"http://haacked.com/archive/2011/10/04/$p$pvent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx\"相对=nofollow>博客一个可行的办法,以规避REST风格的方式来解决此意外的行为。你只需要一个自定义头添加到请求。

Of course some tweaking might be necessary to adapt this to your specific needs. For example you mentioned sending AJAX requests with session expired which might redirect to the Logon page and thus not capturing the error. That's indeed a PITA in ASP.NET. Phil Haack blogged a possible way to circumvent this undesired behavior in a RESTful manner. You just need to add a custom header to the requests.

这篇关于捆绑API请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆