grails cache headers plugin for controllers - grails

This question is not an implementation specific question of the grails plugin, but more of a question illustrated using grails.
Grails a plugin for writing cache related headers (http://grails.org/plugin/cache-headers) and they show an example that looks like
class ContentController
def show = {
cache shared:true, validFor: 3600 // 1hr on content
render(....)
}
}
Since the grails request to get here would look something like http://myapp/content/show, would a browser even try to cache this since it's not a specific resource with a filename (e.g. it's not show.gsp, even though that is what is being used to generate the html)?
What's the purpose of specifying a cache time on dynamic content that won't be cached by the browser (assuming I'm understanding how the browser will cache it based on my statement above)? When might this be useful? Might this be useful in an ajax environment where the user is not typing the full url but rather we're dynamically updating part of a page?

Browser caches URL, not a filename (because HTTP is not a filesystem). I thinks it's the answer for both questions, right?
See:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13
http://www.mnot.net/cache_docs/
https://developers.google.com/speed/docs/best-practices/caching

Related

Web page without real files corresponding to URLs?

geniuses!
I need to make a demo page acting like DBpedia (http://dbpedia.org).
Two pages from different URLs,
http://dbpedia.org/page/Barack_Obama and
http://dbpedia.org/page/Lionel_Messi,
show different content.
I cannot really think DBpedia has million pages for all individual entities (E.g., Barack Obama and Lionel Messi).
How can I handle such URL request?
I know a bit about GET request but example URLs above do not seem like to use GET method.
Thank you in advance!
ps. Please teach me the process. Something like:
1. A user enters URL on a browser.
2. ...
When visiting http://dbpedia.org/page/Barack_Obama, your browser does send a GET request, e.g.:
GET /page/Barack_Obama HTTP/1.1
Host: dbpedia.org
The server (dbpedia.org) receives this GET request and then decides what to do. From the outside, you can’t know (for sure) how the server does something. The two common cases are:
Static web page: a file gets served that exists somewhere on the server. The URL path is often mapped to the server’s file system, but that’s not necessarily the case.
Dynamic web page: a file gets served that is generated on the fly. The content often comes from a database, but that’s not necessarily the case.
After trying some solutions, I'm now using Spring Web MVC framework.
Maybe Dynamic web page solution mentioned in unor's answer.
#Controller
public class SimpleDisplayController {
#RequestMapping("/page/{symbolicName:[!-z]+}")
public String displayEntity(HttpServletRequest hsr, Model model) {
String reqPath = (String) hsr.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String entityLb = reqPath.substring(reqPath.lastIndexOf("/"));
model.addAttribute("label", entityLb);
return "entity";
}
}
I could get request using regex as you can see at the 4th line: #RequestMapping("/page/{symbolicName:[!-z]+}").
The function above returns the string 'entity' which is the name of a HTML file serving as a template.
The following code is a body part of the example HTML template.
<body>
<p th:text="'About entity ' + ${label} + '...'" />
</body>
Since I add an attribute with the key 'label' in the controller above, the template can process ${label}.
In the example HTML template, th:text is a snytax of Thymeleaf (Java library to make an XML/XHTML/HTML5 template) which is supported by Spring.

Grails: Don't Run Filters on a Forward (without using flash variables)

I'm writing a plugin that keeps track of the pages that a user has visited in an application (for the purpose of a back button). It does this by having a filter that runs for every controller/action and keeps a list of visited pages. Everything is working great, except that when used in applications that use forwards, the plugin records two entries for the one page since Grails filters run on every request, even when that request is just a forward (ie: internal redirect).
Since this is a plugin (that has to be application agnostic) I can't simply set a flash variable whenever a forward is used to check if a forward has occurred. Is there any way to determine if a forward has occurred in a filter? I'm exploring the different values in the request variable and how they differ between a normal request and a forward, but things can get quite confusing. Any help is highly appreciated.
P.S. The main difference I noticed so far is that the request.forwardURI and request.requestURI differ for a forward, however, the requestURI is in a special format that I currently don't know how to convert to match the forwardURI.
For example for a normal request:
request.forwardURI = '/short-url' (as set in URLMappings) or '/controller/action
request.requestURI = '/grails/controller/action.dispatch'
For a forward:
request.forwardURI = '/short-url' (as set in URLMappings) or '/controller/action'
request.requestURI = '/grails/forwardedController/forwardedAction.dispatch'

cache issue with redirect

I am having cache issues with a ruby on rails app in internet explorer. On the client side, I am all good because I have used the following jquery code:
$.ajaxSetup({ cache: false });
This adds a string to all urls with a random number like this:
http://www.website.com/?_=418939128471
The dynamically created number solves my cache issues. The problem is that in my controllers, I have many redirects, and since they are on the backend, the jquery code is not applied and certain things that shouldn't be cached are cached. How can i fix the redirects on the backend? I can't switch all of them with renders. I'd also prefer not to change my routes file as my application is quite extensive and changing my routes file would mean changing links throughout the entire application.
Thanks.
You need to simply pass along that random number through your redirects. The number comes through in the params as _, so just give that to your redirect_to methods:
redirect_to some_path('_' => params[:_])
That should fix it, but only do it if that param is present.

CDN/sub-domain, resources, and versioning

I’m hoping to investigate/implement a CDN (initially just via a sub-domain, though moving over to CDN in time) and am having a mare finding resources that talk about handling of versions of files on that sub-domain.
Most places I’ve worked previously have implemented caching of resources (images, javascript, css, etc.) and when wanting to change an image, have gone through the painful process of just changing the filename of the image, and changing the reference to it in the source code (so that customers see the new, not the cached image).
What I want to achieve
what I'd like is:
resources.domain.com
with sub-folders such as:
scripts/
images/
css/
etc.
not a problem, and will help with the yslow/page speed scores (assuming cookieless domain etc.)
But versioning of assets is something I want to resolve.
E.g.
resources.domain.com/images/promo_banner1.jpg
I'd probably have to cache and expire perhaps every 10-15 days.
Assuming we have something key come in as a business request, and we need to change it, I want to be able to override that. From what I understand, I could append a querystring (?1.1) to it to force browsers to see it as a different resource.
I know I can do this in MVC (or indeed ASP.NET) by creating a 'CompanyResource' html helper that will lookup against perhaps a resource file or something similar to see if we have a new version, and if so, append the version number as a querystring element, but there has to be a better way?
So, what has the community come up with?
how best to deal with resources in a sub domain (assume I've read all of the yslow/google backup docs around this)
what have folks come up with to handle versioning of assets (to minimise overall code changes when something updates) - code based helper methods to deliver assets based upon some rules?
Hopefully I haven't waffled too much.
Thanks for any and all help :)
Cheers,
Terry
just noticed this one hadn't been answered - we resovled our problem with Html helpers under ASP.NET MVC using the following.
In web.config we stored the 'resources_url' (in this case resources.mycompany.co.uk), and called the following:
<%= Html.MyCompanyResourceScript("~/scripts/jquery-1.4.2.min.js") %>
Which translated to an Html helper:
public static string MycompanyResourceScript(this HtmlHelper helper, string url)
{
string _out = String.Format(#"<script type=""text/javascript"" src=""{0}""></script>", url.ToMyCompanyUrlAction(helper.ViewContext.HttpContext));
return _out;
}
public static string ToMyCompanyUrlAction(this string url, HttpContextBase context)
{
return String.Format("{0}://{1}{2}",
(context.Request.IsSecureConnection ? "https" : "http"),
WebConfigurationManager.AppSettings["resources_url"],
VirtualPathUtility.ToAbsolute(url, "/"));
}
We created helpers for MyCompanyResourceImage and MyCompanyResourceCss with suitable parameters for alt tags/media types etc. also.
This means we can (from the outset) host via our own resources domain, and if in future we choose to move that over to a CDN, then we can do so with minimal fuss.
Hope that helps someone.
Cheers,
Terry

Correct practices for where to put images and static files in an ASP.NET MVC application?

There is a directory in the standard ASP.NET template "Content" where most people seem to be putting in images and css files etc.
For instance stackoverflow's logo:
(source: stackoverflow.com)
actually is refered to with a server path containing 'content' in the URL (just do View Source for any SO page and you'll see this). So they obviously are storing images in "content/images/...".
src="/Content/Img/stackoverflow-logo-250.png"
Edit: Sometime in the last 10 years they changed the path - but this is what it used to be.
I dont particularly like this. My HTML ends up with /content all over it, and its slightly harder to migrate existing pages that just have /image. Fortunately my stylesheet doesnt end up with content all over it, as long as I save it in content\site.css.
An alternative is to put an images directory in the root, but then you get images at the same level as Controllers and Views which is pretty horrible.
I'd wondered about trying to add a redirection rule like this :
routes.RedirectRoute(
"images rule",
"Images/{*}",
"Content/Images/{1}"); // this is NOT valid code - I made it up
But that code doesnt work because I just made it up. I could use a third party redirection/rewriting plug-in but I want to keep everything 'pure' within the MVC model.
What has anyone else found in this area? Or is everyone just happy with an extra ("/content".length) bytes in their source for every image they serve.
To be honest, I don't think its really something to worry about... "/Content" is going to make a pretty minimal contribution to your page size. If you still want to do it, here are some options:
Option 1, if you are running on your own server, is to check out the IIS URL Rewrite module: http://learn.iis.net/page.aspx/460/using-url-rewrite-module/
Option 2 is to use either RedirectResult, or ContentResult, to achieve the same effect in the MVC framework
First, map a "catchall" route under "Images/" to a controller action, like so
routes.MapRoute("ImageContent",
"Images/{*relativePath}",
new { controller = "Content", action = "Image" })
Make sure it is above your standard "{controller}/{action}/{id}" route. Then, in ContentController (or wherever you decide to put it):
public ActionResult Image() {
string imagePath = RouteData.Values["relativePath"]
// imagePath now contains the relative path to the image!
// i.e. http://mysite.com/Images/Foo/Bar/Baz.png => imagePath = "Foo/Bar/Baz.png"
// Either Redirect, or load the file from Content/Images/{imagePath} and transmit it
}
I did a quick test, and it seemed to work. Let me know in the comments if you have any problems!
It's usually better to put images under a different sub domain. The reason for this is browsers limit the number of connections per URL. So if you use http://static.mysiste.com now the browser can open more concurrent connections due to it being in a different URL.

Resources