JAX-RS REST service + EJB on WildFly 10, always adds no-cache HTTP header in responses - ejb

I have wrote a stateless EJB that provides a rest service.
I am working with the Wildfly 10 application server and developing with the Netbeans IDE.
I have tried to cache the return values of few methods for few hours by adding a max-age header in the http-response of the service methods. Please consider this is a simplified version of my bean:
#Stateless
#DeclareRoles({"role1","role2"})
#RolesAllowed({"role1","role2"})
#Path("api-dummy")
public class DummyApiREST {
#EJB
private StuffFacade stuffFacade;
#GET
#Path("get-stuff")
#Produces({MediaType.APPLICATION_JSON})
public Response findStuff() {
Stuff stuff = stuffFacade.getStuff();
Response.ResponseBuilder builder = Response.status(Response.Status.OK).entity(stuff);
Utils.setCacheHeader(maxAgeSeconds, builder);
return builder.build();
}
}
And the setCacheHeader method:
private static Response.ResponseBuilder setCacheHeader(int maxAgeSeconds, Response.ResponseBuilder builder) {
CacheControl cc = new CacheControl();
cc.setNoCache(false);
cc.setNoStore(false);
cc.setMaxAge(maxAgeSeconds);
cc.setPrivate(true);
builder.cacheControl(cc);
return builder;
}
But the returned response of "get-stuff" always contains a duplicate of the Cache-Control header; the duplicate header contains no-cache directives (the is also a Pragma header):
HTTP/1.1 200 OK
Expires: 0
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control: no-transform, max-age=60, private
X-Powered-By: Undertow/1
Server: WildFly/10
Pragma: no-cache
Date: Thu, 13 Apr 2017 15:11:17 GMT
Connection: keep-alive
Content-Type: application/json
I suppose the problem is caused by a default behaviour--or filter-- for the JAX-RS services in my EJBs. My questions are:
Is there a better way to set the max-age and enable caching in JAX-RS + EJB?
Is there a way to disable this no-cache default behaviour? (OR in other words, where is this usually configured?)
..and..what is wrong in my solution? :-)
NOTE: Perhaps it is not related, I have configured a jdbc security-domain and users authenticate and principal(s) work well.
Regards

I have found the solution.
By default Wildfly (and I think JBoss too) adds the no-cache directives to all the private resources (resources that needs authentication).
You have to change the configuration in standalone.xml file, by adding an attribute disable-caching-* to the server-container tag:
<servlet-container name="default" disable-caching-for-secured-pages="false">
<jsp-config/>
<websockets/>
</servlet-container>
In this way no more Pragma and nocache directives will be added to responses and the code I posted in my question, it simply works as expected.
EDIT: Remind, when requests for private resources, at the same URL, have to return different contents to different users you have to:
add the private header to that responses, for your reverse proxy to
not cache that content OR in alternative..
..left the nocache header there for that responses

Related

Specific location path is not refreshing

We have a OpenResty, Nginx and Redis stack. I have a location block in my nginx.conf which doesn't reponse to any changes I do.
I have a Lua module function that is invoked by location in nginx.conf. The function is like:
function _M.myFunction()
ngx.header["Content-Type"] = "text/html"
ngx.say("debug")
end
I have a location like this - this location was set to another function that returned text/plain Content-Type with an empty string (ngx.say(" ") and I now pointed it to my debug function, it seems that it is "stuck" on previous response:
location /.faulty/foo/{
content_by_lua_block {
myLuaModule:myFunction()
}
}
responding with:
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
with no body in response.
Testing by adding a different locations seems to working great for the same function and getting me the response I want:
location /.test/foo/{
content_by_lua_block {
myLuaModule:myFunction()
}
}
responding with:
HTTP/1.1 200 OK
Content-Type: text/html
Connection: keep-alive
debug
I checked Redis for any key that might hold this location, and couldn't find anything relevant.
so, for future generations -
there was a LB server in front of that server with the exact same function and location.
once changed there the change was refreshed.

Varnish + Wordpress + Nginx - Prevent no-store no-cache must-revalidate headers

We launched a web app about a week ago, experienced a heavy load spike and were down for almost 2 hours. I won't mention the company by name, but we were leaning on them for recommendations to prevent this exact thing.
They said that since we were using Varnish, we could handle the traffic influx quite easily. However, we didn't verify caching was working as intended. It was not.
TLDR: Our web app is sending Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 headers with requests and there's no indication of why that is.
Where can I look to prevent these headers from being sent?
PHP: 5.6
Nginx: 1.4.6
Varnish: 1.1
Wordpress: 4.6.12
Timber: 1.2.4
The linux admins we're working with have said they scoured the configs and haven't found anything specifying those headers except for AJAX requests.
#dont cache ajax requests
if(req.http.X-Requested-With == "XMLHttpRequest" || req.url ~ "nocache" || req.url ~ "(control.php|wp-comments-post.php|wp-login.php|bb-login.php|bb-reset-password.php|register.php)")
Here's a curl from Pre-launch when we correctly configured Varnish to cache after forcing HTTPS(force-https plugin) on the site:
$ curl -Ik -H'X-Forwarded-Proto: *************
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Content-Type: text/html; charset=UTF-8
Vary: Accept-Encoding
X-Server: *****
Date: Sat, 03 Nov 2018 22:36:43 GMT
X-Varnish: 53061104
Age: 0
Via: 1.1 varnish
Connection: keep-alive
And from post launch:
curl -ILk ***********
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
X-Varnish: 691817320
Vary: Accept-Encoding
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Type: text/html; charset=UTF-8
X-Server: ****
Date: Mon, 19 Nov 2018 19:17:02 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Pragma: no-cache
Transfer-Encoding: chunked
Accept-Ranges: bytes
Via: 1.1 varnish
Connection: Keep-Alive
Set-Cookie: X-Mapping-fjhppofk=33C486CB71216B67C5C5AB8F5E63769E; path=/
Age: 0
Force-https plugin: We activated this, updated the Varnish config to avoid a redirect loop and confirmed it was working a week prior to launch.
Plugins: These did not change, except for force-https.
Web App: It's an updated version of the previous app, complete redesign but nothing in the app from what I can tell is specifying no-store no-cache headers to be sent.
Where should I start? Thanks!
What is sending these headers is PHP engine.
It does so whenever you initiate a session, which clearly happens based on Set-Cookie presence.
Make sure that PHP sessions are initiated only when absolutely needed. By default, Varnish will not cache when response includes either Set-Cookie or "negative" Cache-Control, you have both.
So getting rid of extraneous session_start() and/or setcookie() calls is the key here.
You can find more info on when you can expect anti-caching headers sent here.
You need to fix the backend, but at the very least, you can strip the annoying header, and/or bypass it in varnish with this vcl snippet;
sub vcl_backend_response {
# kill the CC header so that application downstream don't see it
unset req.http.Cache-Control;
# alternatively, you can also override that header with
# set req.http.Cache-Control = "whatever string you desire";
# you can also force the TTL
beresp.ttl;
# also, if you return now, the builtin.vcl (https://github.com/varnishcache/varnish-cache/blob/master/bin/varnishd/builtin.vcl)
# doesn't get executed; this is generally the one deciding content is uncacheable
return (deliver);
}

Why does my Web API return 404 on all resources when called from a Console app?

I have a little Web API, almost directly from the standard VS project template, i.e. Home and Values controllers, and lots of MVC cruft. It is set to run and debug under IIS 10.
I have set up tracing by adding the package Microsoft.AspNet.WebApi.Tracing and the following code in WebApiConfig:
public static void Register(HttpConfiguration config)
{
config.EnableSystemDiagnosticsTracing();
SystemDiagnosticsTraceWriter traceWriter = config.EnableSystemDiagnosticsTracing();
traceWriter.IsVerbose = true;
traceWriter.MinimumLevel = TraceLevel.Debug;
config.Services.Replace(typeof(ITraceWriter), new SimpleTracer());
...
...
}
SimpleTracer is an ITraceWriter that writes to a text file.
When I call the API from outside the VS ecosystem, i.e. from PostMan in Chrome, a bad url, that results in a 404 error message, and the creation of a new trace file if there's not already one. Of I call it from PostMan with a good url, I get the expected result, and a trace of the request in the trace file.
When I call it from my Console app, even with a good url, I still get a 404 error response, and nothing is written to the trace file. I made sure by removing it and IIS doesn't even re-create it when using the .exe client.
If I call it from the compiled .exe from outside VS, I get the same error.
Then, when I set the Web API to use IIS Express, everything works perfectly. Do I need CORS for calls from non-web apps, does IIS need an extra header in this case? What is wrong?
EDIT A: This is the request when I use PostMan, and it returns a 200 and the expected list of strings.
GET /DemoApi/api/values HTTP/1.1
Host: localhost
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: f9454ffc-6a8d-e1ed-1a28-23ed8166e534
and the response and headers:
["value1","value2","value3","value4","value5","value6","value7"]
Cache-Control →no-cache
Content-Length →64
Content-Type →application/json; charset=utf-8
Date →Tue, 13 Dec 2016 06:20:07 GMT
Expires →-1
Pragma →no-cache
Server →Microsoft-IIS/10.0
X-AspNet-Version →4.0.30319
X-Powered-By →ASP.NET
EDIT B: This is the request sent using HttpClient:
GET http://abbeyofthelema/api/values HTTP/1.1
Accept: application/json
Host: abbeyofthelema
Connection: Keep-Alive
The only real difference is that because Fiddler doesn't capture traffic from localhost, I had to use my computer name instead. The same recipient still gets the request.
The response here is:
HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 13 Dec 2016 08:07:25 GMT
Content-Length: 4959
According to Timothy Shields at the following link
Why is HttpClient BaseAddress not working?
You must place a slash at the end of the BaseAddress, and you must not place a slash at the beginning of your relative URI

Preventing 304 NOT MODIFIED response in Tomcat

If a resource (index.html) is already cached in the client, for example using response header:
"Cache-Control": "max-age=0, must-revalidate, proxy-revalidate"
How can I prevent tomcat to respond with a 304 Not Modifiedin the next request to the server? I would like to force the server to respond with 200 instead of 304 no matter what.
I tried to set
httpResp.setHeader("Cache-Control", "no-cache, no-store, must-revalidate, proxy-revalidate");
httpResp.setHeader("Pragma", "no-cache");
httpResp.setHeader("Expires", "0");
but it only works in the SECOND request. The first request still gets 304.
I tried to override the if-modified-since header using HttpServletRequestWrapper with values in the past such as Mon, 06 Dec 2010 01:34:46 GMT with no luck - client still gets 304 responses although the file was modified in 2015.
Is there any way I can prevent 304 responses? maybe via tomcat configuration?
Not sure if this will help but you could try the following -
Delete the browser cache to start from scratch and test whether this works or not
Adapted from another ServerFault question -
https://serverfault.com/questions/40205/how-do-i-disable-tomcat-caching-im-having-weird-static-file-problems?answertab=votes#tab-top
You might have to delete the application cache folder in /work/Catalina/localhost after changing the cachingAllowed flag.
Configuration can be introduced in server.xml as
<Context className="org.apache.catalina.core.StandardContext"
cachingAllowed="false"
charsetMapperClass="org.apache.catalina.util.CharsetMapper"
cookies="true"
reloadable="false"
wrapperClass="org.apache.catalina.core.StandardWrapper">
</Context>

401 error when using a web service in sapui5

I am implementing a web service into my sapui5 table by
var oModel = new sap.ui.model.odata.ODataModel("http://mywebservice.com/security.svc", false);
sap.ui.getCore().setModel(oModel);
When I launch my code in a web browser and inspect element, I am getting the following errors:
Failed to load resource: the server responded with a status of 401 (Unauthorized)
XMLHttpRequest cannot load http://mywebservice.com/security.svc/$metadata. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:53457' is therefore not allowed access. The response had HTTP status code 401.
I also tested it in Fiddler and I get:
HTTP/1.1 401 Unauthorized
Cache-Control: private
Server: Microsoft-IIS/8.0
Set-Cookie: ASP.NET; path=/; HttpOnly
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
Date: Tue, 09 Jun 2015 19:33:51 GMT
Content-Length: 0
Proxy-Support: Session-Based-Authentication
Any help on how to fix the 401 error would be greatly appreciated.
Creating a new ODataModel, it tries to fetch the metadata for the service you have called.
It's basically XMLHttpRequest to a different domain(http://mywebservice.com) than you page(localhost) is on.So the browser is blocking it as it usually allows a request in the same origin for security reasons. Read about same-origin policy
Solution:
You need to do something different when you want to do a cross-domain request.
the origin (where the page with JavaScript is at) and the target: http://mywebservice.com (where the JavaScript is trying to reach) domains must be the exact same.
A tutorial about how to achieve that is Using CORS.
In .NET server,you can configure this in web.config as below
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="your_clientside_websiteurl" />
</customHeaders>
</httpProtocol>
<system.webServer>
Just clone the shortcut for chrome on your desktop, and then in the shortcut properties add the parameter --disable-web-security at the end of chrome executable path
e.g
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-web-security
NB:add that parameter --disable-web-security in Target location after one space

Resources