Reputation: 2211
I have an Angular 5 application that tries to load products over an HTTP-GET API call and crashes on iOS Safari and Mac OS Safari.
The first time I access the page everything works fine but after the second time my Angular application crashes because the HTTP-GET doesn't return the expected values.
I checked the developer console and it turns out that Safari doesn't send the cookies from my domain that are required for the GET to work.
It says that the Request came from the hard drive cache.
I checked the log files on my server and Safari actually calls my API (despite it saying it used the hard drive cache) but without the cookies.
The HTTP-GET from my Angular application looks like this:
this.noCacheHeader = new HttpHeaders()
.append('Cache-Control', 'no-cache')
.append('Cache-control', 'no-store')
.append('Expires', '0')
.append('Pragma', 'no-cache');
get<T>(url: string): Observable<T> {
return this.http.get<T>(this.baseUrl + url, { withCredentials: true, headers: this.noCacheHeader });
}
I'm already disabling caching because of caching troubles with IE11.
What can I do to tell Safari to always send my cookies?
Update 1:
I added a ticks parameter to my HTTP-GET query "products?ticks=1337" and now it works. So it must have something to do with caching.
Upvotes: 4
Views: 4128
Reputation: 305
It may not be the same, but I had the similar issue with Safari. I was using <audio>
tag inside the html loaded by jquery. Safari did not include cookies in the request for the audio source, therefore it did not load properly. But somehow it worked after I refreshed the page with CTRL+F5 - it sent cookies with this total reload...
I solved it by adding crossorigin="use-credentials"
... Nasty problem.
Upvotes: 2
Reputation: 34593
One approach is to use a custom Http Interceptor:
// custom.interceptor.ts
@Injectable()
export class CustomHttpInterceptor implements HttpInterceptor {
intercept (httpRequest: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
const clonedRequest = httpRequest.clone({
withCredentials: true
});
return next.handle(clonedRequest);
}
}
Then reference the interceptor in your app.module.ts
:
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { CustomHttpInterceptor } from 'your-module;
@NgModule({
...,
imports: [
...,
HttpClientModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: CustomHttpInterceptor,
multi: true
},
],
})
withCredentials: true
is the important part of the interceptor. Setting this option should pass cookies back on every request.
See: https://angular.io/api/http/RequestOptions and https://fetch.spec.whatwg.org/#cors-protocol-and-credentials for more information.
If you're already doing that, it's likely a caching issue. Try setting the Cache-Control
header to be more restrictive:
setHeaders: {
"Cache-Control": "private, no-cache, no-store, must-revalidate"
}
or finally, append a querystring parameter to the request that is always unique, like a UNIX timestamp.
Upvotes: 0