Closed Saphirim closed 4 years ago
No, server push will not be available in any AspNetCore servers for 2.2. We're still trying to gauge interest for 3.0.
Interest here 😊 thx for your fast reply.
Same here.
If not 2.2 then 3.0 will be nice
🙋🏼♂️ I would love to have the ability to push resources over an established HTTP/2 connection with ASP.NET.
It would help if you can detail how you think you would take advantage of this feature in real applications. Code samples help as well.
I would like to use HTTP/2 Server Push to push related resources to a client; typically when a “collection” resource has been requested, each “item” resource in the collection could be pushed alongside the “collection” resource so they are available once the client starts iterating over the collection to fetch the individual items.
The alternative (and imho. sub-par) approach is to compound (“embed”, “transclude”, “include”, “expand”, etc.) all items within the collection resource, making caching of the collection resource hard and of the item resources impossible.
The relationship between the resources can also be seen as “parent” and “child”, “root” and “subresource”, etc., but the requirements are similar regardless of the relationship between the resources. Server push could provide helpful in all cases.
How does that concretely change what you’re doing today? What are you doing today? What big downsides are you seeing and what would you expect the big upside to be.
I’m looking for something very concrete and not abstract, that’ll help us think about how to prioritize and even implement the feature.
@davidfowl, sure. Examples of how we (as an industry) deal with the problem of transclusion over HTTP/1.1 today can be found in GraphQL and OData. In GraphQL, transclusion is expressed as sub-selection:
POST /query HTTP/1.1
Host: example.com
Content-Type: application/graphql
{
hero {
friends {
name
height
}
}
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker",
"height": 1.72
},
{
"name": "Han Solo",
"height": 1.85
},
{
"name": "Leia Organa",
"height": 1.54
}
]
}
}
}
In OData, transclusion is expressed with the $expand
keyword:
GET /heroes/r2-d2?$expand=friends($select=name,height) HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Content-Type: application/json
{
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker",
"height": 1.72
},
{
"name": "Han Solo",
"height": 1.85
},
{
"name": "Leia Organa",
"height": 1.54
}
]
}
}
Each friend
in the above responses are most likely HTTP resources themselves. There's no information provided that allows REST's layered constraint to be used to allow intermediary caching, resource-level RBAC or other resource-specific optimizations, since every "sub-resource" is compounded into one large response.
With HTTP/2, we can use Server Push to deliver each hero
as its own resource instead. Hypothetical example based on @evert's Prefer-Push
draft:
GET /heroes/r2-d2 HTTP/2
Prefer-Push: friends
Host: example.com
HTTP/2 200 OK
Content-Type: application/json
{
"hero": {
"name": "R2-D2",
"friends": [
{
"id": "https://example.com/heroes/luke-skywalker"
},
{
"id": "https://example.com/heroes/han-solo"
},
{
"id": "https://example.com/heroes/leia-organa"
}
]
}
}
Following this response, three PUSH_PROMISE
frames will be sent by the server; one for each friend
:
:path /heroes/luke-skywalker
:authority example.com
:path /heroes/han-solo
:authority example.com
:path /heroes/leia-organa
:authority example.com
Then three HEADER
and DATA
frames are sent by the server containing the headers and contents of the three hero resources:
Content-Type: application/json
{
"hero": {
"name": "Luke Skywalker",
"height": 1.72,
"friends": [
{
"id": "https://example.com/heroes/r2-d2"
},
{
"id": "https://example.com/heroes/han-solo"
},
{
"id": "https://example.com/heroes/leia-organa"
}
]
}
}
Content-Type: application/json
{
"hero": {
"name": "Han Solo",
"height": 1.85,
"friends": [
{
"id": "https://example.com/heroes/r2-d2"
},
{
"id": "https://example.com/heroes/luke-skywalker"
},
{
"id": "https://example.com/heroes/leia-organa"
}
]
}
}
Content-Type: application/json
{
"hero": {
"name": "Leia Organa",
"height": 1.54,
"friends": [
{
"id": "https://example.com/heroes/r2-d2"
},
{
"id": "https://example.com/heroes/luke-skywalker"
},
{
"id": "https://example.com/heroes/han-solo"
}
]
}
}
Now that each hero has been pushed with its own URI, intermediaries can cache them, authorize them, individually on a per-resource basis. This also has two added bonuses:
R2-D2
response will be more cacheable by being less tailored to the initial request.How we should signal pushing of resources from the client to the server is still up for discussion. preload
and prefetch
are both viable options that are being investigated. Regardless of the initiation mechanism, a way to do HTTP/2 Server Push in an ASP.NET Core application is needed.
Same scenario as above, we currently preload those as soon as we get the headers, before we parse the body, so we have headers -> links -> download body (and download links in the background), and finally reassemble once parsing has been done for the request entity body. We lose quite a bit of time in that model, and we have to maintain client code and specific infrastructure for it, which is a pain. People don't like pain. It's a good model. We can't experiment further with push as a replacement because of the lack of implementation.
For what it's worth, Nginx supports HTTP/2 push (see https://www.nginx.com/blog/nginx-1-13-9-http2-server-push/), so if you're using Nginx as a reverse proxy in front of your ASP.NET service, you just have to enable the http2_push_preload
option and send the relevant preload Link
headers and Nginx will convert that into a HTTP/2 push for you.
@Daniel15 This is bad replace for real HTTP/2 Server Push support cuz of:
NGINX intercepts this header and commences a server push of /style.css. The path in the Link header must be absolute – relative paths like ./style.css are not supported
Adding additional configs in Nginx for cover this isn't right answer
+1 for adding Server Push support. That way we could implement something like Vulcain directly instead of having to use their Gateway Server for the Server Push support.
Does. Net core 3.1 supports HTTP/2 Server push?
No it does not
Should we expect its support in .Net Core any time soon?
No, we're not working on this feature. The cost is high and it isn't a priority for the current release.
How about .Net 5, any plans to consider it for next major release?
.NET 5 is the currrent release, so do you mean .NET 6? Sure nothing has been planned for that as yet.
Thanks @davidfowl, I thought .Net Core 3.x is considered as current release.
HTTP/2 server push can have major effect on the performance of web applications since it can improve page load time by pushing the required resources in a single request. And now most of the browsers support this feature, don't you think its support should be added to one of the most popular web development platform?
Ref: https://developers.google.com/web/fundamentals/performance/http2#server_push
HTTP/2 server push can have major effect on the performance of web applications
These benefits are largely theoretical and come with a lot of issues of their own (e.g. cache busting). The various standards groups are still trying to make it work in practice.
Sorry current release as in the one we are currently working on. We already have planned and have started working on .NET 5 for a few months now.
I'd like to see push support to be able to send messages to a REST API client from the server. I've just started playing with HTTP2 but failed immediately and can't recover. So I went on and checked push support. Now that I see it's not there and not coming in the foreseeable future, I can give up on HTTP2 altogether. This means I need to find another solution to send events through a REST API (or something similar and lightweight).
PS. It's a local connection, so nothing over a network. Maybe classic .NET remoting would work here. 😆
@ygoe HTTP/2 PUSH is not an event API, the client still has to request the resource from the HTTP stack. You should look at WebSockets, SignalR, etc..
To pile on on to @tracychms , HTTP/2 Push is really a mechanism to 'warm the cache' and send responses to GET requests that the client will need to make soon anyway. It removes a potential round-trip. Still useful for speeding up APIs
OK, must have misunderstood this. But hasn't there been such a message send thing somewhere around HTTP a few years ago? Or was that WebSocket only?
Websocket enables server-initiated messaging to a browser, and it piggybacks on HTTP/1.1 to initiate the connection. Websocket over HTTP/2 will use HTTP/2 frames.
I think there was a lot of misunderstanding over what HTTP/2 Push meant. If it's helpful I wrote something about the use-case of HTTP/2 push in the context of APIs: https://evertpot.com/h2-parallelism/
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
For reference, System.Web API for this - https://docs.microsoft.com/en-us/dotnet/api/system.web.httpresponse.pushpromise?view=netframework-4.8
Further reference, this is being removed from chrome https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ
Almost five and a half years after the publication of the HTTP/2 RFC, server push is still extremely rarely used. Over the past 28 days, 99.95% of HTTP/2 connections created by Chrome never received a pushed stream (Net.SpdyStreamsPushedPerSession), and 99.97% of connections never received a pushed stream that got matched with a request (Net.SpdyStreamsPushedAndClaimedPerSession). These numbers are exactly the same as in June 2019. In June 2018, 99.96% of HTTP/2 connections never received a pushed stream. These numbers indicate the lack of active efforts by server operators to increase push usage. On top of this, less than 40% of received pushes are used, down from 63.51% two years ago. The rest are invalid, never get matched to a request, or already in cache.
Thanks for sharing, @davidfowl. First I have to say that the Chrome developers are overly impatient. For complex enough concepts and technologies, 5 years is nothing. Two examples:
Secondly, I believe server push to be much more useful with fine-grained control in API use cases than it has been in browsers. Browser support is thus not very relevant, at least not for the use cases I've envisioned.
Hi @davidfowl,
It looks the intent is to pivot toward 103 Early Hints as Chrome has recently started an experiment to evaluate their effectiveness.
It looks like, similar to Server Push, this is not something which can be added on top of ASP.NET Core in .NET 5, unless I'm missing an extensibility point which allows emitting informational responses for HTTP/2.
Is this something which could be tracked/considered for .NET 6 (depending on that experiment results)?
Yes 103 Early hints would require new API, please open a new issue for that. It would be pretty strait forward in Kestrel. This new feature isn't HTTP/2 specific, it should work with any version.
Note 1xx responses are so uncommon that to enable this on IIS/Http.Sys would require work in Http.Sys at the OS level. Only 100 Continue and 101 Switching Protocols are supported today, and those are both managed closely by Http.Sys, ASP.NET and IIS have minimal control over them.
Two examples
Add to that IPv6. 25 years or so old and Vodafone still has no clue what that is or that it exists while other providers have almost switched off IPv4 a few years ago.
Glancing over the Google comment, it seems like Push is not very helpful but overly complex. I also had no intentions to make use of Push.
@Tratcher I've created #27851
Reposting @davidfowl's earlier comment from Chrome's intent to remove HTTP/2 server push
Almost five and a half years after the publication of the HTTP/2 RFC, server push is still extremely rarely used. Over the past 28 days, 99.95% of HTTP/2 connections created by Chrome never received a pushed stream (Net.SpdyStreamsPushedPerSession), and 99.97% of connections never received a pushed stream that got matched with a request (Net.SpdyStreamsPushedAndClaimedPerSession). These numbers are exactly the same as in June 2019. In June 2018, 99.96% of HTTP/2 connections never received a pushed stream. These numbers indicate the lack of active efforts by server operators to increase push usage. On top of this, less than 40% of received pushes are used, down from 63.51% two years ago. The rest are invalid, never get matched to a request, or already in cache.
Given that HTTP/2 server push was intended as a performance optimization and studiessup>[\[1\]](https://github.com/httpwg/wg-materials/blob/gh-pages/ietf102/chrome_push.pdf)[\[2\]](https://github.com/httpwg/wg-materials/blob/gh-pages/ietf102/akamai-server-push.pdf)[\[3\]](https://medium.com/@ananner/http-2-server-push-performance-a-further-akamai-case-study-7a17573a3317)</sup have shown little to no performance improvements, the ASP.NET Core team has decided not do this.
[1]: https://github.com/httpwg/wg-materials/blob/gh-pages/ietf102/chrome_push.pdf [2]: https://github.com/httpwg/wg-materials/blob/gh-pages/ietf102/akamai-server-push.pdf [3]: https://medium.com/@ananner/http-2-server-push-performance-a-further-akamai-case-study-7a17573a3317
Support the HTTP/2 Server Push feature with the now previewed and for .Net Core 2.2 most likely GA HTTP/2 implementation.