-
Notifications
You must be signed in to change notification settings - Fork 38.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance impact of ResourceUrlEncodingFilter on HttpServletResponse#encodeURL #27538
Comments
This is sub-optimal indeed, but by default Spring Boot maps static resources on This isn't too much of an issue when handling incoming requests since controllers are checked before static resources, but for Perhaps, |
Would it be an option to reimplement |
@schosin It looks like this is related to #27541 - which I currently have in the works for 5.3.11 - and originally #21372 which led to a reimplementation of While As far as I see right now, overriding |
I've made a change to filter out non-existing locations. In the given scenario, with default Boot settings and use of WebJars, it filters out 4 and leaves 1 location (ServletContextResource '/'). Using the sample with 10K and 100K links, I see a significant reduction of processing time, by more than a third. That should complement the other change to improve |
This is available in the latest 5.3.11 snapshot now and will be available in the upcoming 5.2.18 snapshot as well. Feel free to give it an early try... |
@rstoyanchev and @jhoeller we recently upgraded to spring-boot 2.5.6 which I think includes these changes, and static content (included in a JAR file inside the executable spring-boot JAR) is not found anymore. This static content is an angular application and in spring-boot 2.5.5 it is found and works OK but not in 2.5.6. Could it be that the behavior we see is caused by these changes? Is it required to update any application property or do something extra to allow spring to find static content inside JAR files (included in the spring-boot executable JAR)? |
@silver-mx it could be, but it's hard to tell from your comment. Could you share a sample application (something we can download or git clone) so that we can reproduce this problem? |
@bclozel I cannot share the application as is but I will try to come up with a simpler version that hopefully reproduces the issue. Thanks! |
Unfortunately, I have not been able to reproduce the issue with a simpler application, but I enabled the debug logs in our application and I can see the following log, which lists the paths where resources are found: When static resources are found (spring-boot 2.5.5)
When static resources are NOT found (spring-boot 2.5.6)
NOTE: Our resources are in this case placed in The logs were obtainer sending a simple request to |
@silver-mx without a project reproducing the error, it's going to be hard to help you. When your application starts up, does the |
@bclozel The resources are placed in a JAR contained in the I have not given up trying to create an application that reproduces the issue, but based on the traces I have shared we can see that spring-boot 2.5.6 does not seem to consider |
It might be that the location is considered as missing and filtered out. I'll work on a sample if you can confirm the following: can you add an |
I wonder if this could be caused by the jar not containing entries for its directories? For example, if |
@bclozel and @wilkinsona I can confirm that adding In summary: WITHOUT
WITH
So it looks like spring filters out |
@silver-mx adding a I've tested this very scenario with an application that depends on a JAR that's built with Gradle and only contains repackaged static resources (generated by webpack). With Spring Boot 2.5.6, static resources are still found and I can't reproduce this issue. Looking at the jar, I can see an entry for the
Could you check that the jar containing static resources is missing that entry? Could you elaborate on how it's being built? |
@bclozel I see that the JAR has the static folder:
Not completely sure how it is being built as it comes as a maven dependency. Do you suspect that the format could be wrong? Created like a ZIP instead of a JAR of something? |
@silver-mx this confirms that the |
@bclozel I am confused, the JAR contains a |
@silver-mx it's missing an entry for the |
@bclozel and @wilkinsona thanks, I was not understanding what you meant as |
FYI this change broke static resource handling on Spring Native side since even with native configuration only the file resources are available, not the directories. Short term, I will try to craft a substitution to disable this optimization on Spring Native side. I am wondering if we should disable this optimization on native in next Spring Framework release, or if we want to refine this mechanism one way or another. We can maybe raise a bug on GraalVM side if we think this is the right thing to do but it will take several months to be fixed. |
New update: this issue only happens with GraalVM 21.2.0 and seems to not be present with GraalVM 21.3.0. So if confirmed, I will just provide a substitution for Spring Native 0.10.x based on GraalVM 21.2.0 and Spring Native 0.11.x based on GraalVM 21.3.0 should be fine. |
It's valid for a jar file to be created without entries for its directories. IMO, the optimisation needs to be refined to check for the existence of anything matching |
I've created #27624 to follow up on this. |
See #27624 for an update: This existence check is behind an |
This avoids Spring doing resource resolution for every link on page which seems to cost us over 100ms on some pages in some environments. See: spring-projects/spring-framework#27538
Affects: Spring Framework 5.3.10
Prior discussion: https://gitter.im/spring-projects/spring-boot?at=615ffdb17db1e3753e2ba6f9
Repository showcasing the issue: https://github.com/schosin/ResourceUrlEncodingFilterPerformance
When using
ResourceUrlEncodingFilter
with its default configuration, invocations of HttpServletResponse#encodeURL will be wrapped byResourceUrlEncodingResponseWrapper
, which resolves URLs according to aResourceUrlProvider
.With
WebJarAssetLocator
present, this will catch all URLs (/**) and test against five different locations whether the URL passed is a static resource:[class path resource [META-INF/resources/], class path resource [resources/], class path resource [static/], class path resource [public/], ServletContext resource [/]]
For class path resources, this is done by resolving the path against the resource folder and checking calling
Resource#isReadable
, which ultimately throws a FileNotFoundException if the resource is not present. SeePathResourceResolver#getResource(String, HttpServletRequest, List<? extends Resource>)
.Since simple URLs to any handler mappings cause these checks, pages with many links will have poor performance, especialy on machines with weaker CPUs.
A workaround is to disable Spring's default resource handling (spring.web.resources.add-mappings) and registering custom resource handlers mapping handlers directly (e.g. "/css/** -> classpath:/static/css/").
The text was updated successfully, but these errors were encountered: