Safari on iOS and OSX CORS Problem.

17,802 views
Skip to first unread message

Jörg Zimmer

unread,
Dec 3, 2014, 7:55:52 AM12/3/14
to ang...@googlegroups.com
Hi there,
I'm having some trouble with my angular-app on iDevices.
My REST backend is on a different domain with all neccessary headers set (CORS). Requests to app and REST are done via HTTPS.

When a REST call is done by a service, I see an OPTIONS request to the server with the appropriate result XML...
The following GET request fails on both iOS and OSX.
The safari-console shows a successful 200 returncode but with the same XML-result as the OPTIONS call. Not the expected result from the api.
Apache is only logging the OPTIONS request. No GET.

This only happens on Safari on iOS and OSX.
Different browsers are working fine. On windows everything is working. Even in Safari.

I can't see my mistake.
Any ideas?!

Best regards 
Joerg

Jörg Zimmer

unread,
Dec 3, 2014, 8:07:03 AM12/3/14
to ang...@googlegroups.com
Just tested the app on the same domain as the REST api.
No more Problems.
So the error is caused by the different domain the api is running on.
Strange though, that on all other browsers everything is working fine.
Where is that little switch that apple is awaiting among the others?

Jonathan Price

unread,
Dec 4, 2014, 2:42:40 AM12/4/14
to ang...@googlegroups.com
We recently had similar problems that stemmed from not using the full url path on requests in our api.  All browsers worked fine, but not the ios devices.

Jörg Zimmer

unread,
Dec 4, 2014, 10:39:02 AM12/4/14
to ang...@googlegroups.com
Hi Jonathan,

as the api is running on it's own domain, we sure have the full url path in our request.
Or what exactly do you mean by "full"

Joerg

Puritan Paul

unread,
Dec 4, 2014, 3:10:05 PM12/4/14
to ang...@googlegroups.com

We initially had just a relative path in out client requests.  I'll bet this isn't your problem. I only mentioned it because the symptoms were similar. 
--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/3hP4JpTHLYY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Jörg Zimmer

unread,
Dec 9, 2014, 4:15:46 AM12/9/14
to ang...@googlegroups.com
just found something new.
Devices with iOS7 or OSX Mavericks with Safari 7.x are working fine.
Seems to be something new on the latest release

Rob Koberg

unread,
Jan 20, 2015, 9:00:45 PM1/20/15
to ang...@googlegroups.com
I am running into this problem too. My app works on everything except iOS8. Did you find a fix for this? It seems like iOS 8 is sending a bad request to the server and not getting past apache to go into my server side app.

Jörg Zimmer

unread,
Jan 21, 2015, 3:46:52 AM1/21/15
to ang...@googlegroups.com
Hi,
we are currently running our app with a message to iOS8 Users...
A temporary this is to use the same Domain for API and Website... But this is not acceptable in the final product.

This seems like a bug to me. I also found this one:

which links to this:

Seems to relate to the problem...
If you find a final solution please share...

Rob Koberg

unread,
Jan 21, 2015, 12:45:14 PM1/21/15
to ang...@googlegroups.com
GOT IT! This is very difficult to debug. Chrome on iOS8 works. My local Safari emulating the iOS8.1 user agent works locally, but not on the server. The iPad emulator that comes with XCode works on the server and locally.

For the preflight OPTIONS request, I am seeing Safari send:
Access-Control-Request-Headers accept, authorization, origin

Where other browsers send (no origin):
Access-Control-Request-Headers accept, authorization

So I added Origin:
Header always set Access-Control-Allow-Headers "X-Accept-Charset,X-Accept,Content-Type,Authorization,Accept,Origin"

But still not working. (there is a mention of this here: http://stackoverflow.com/questions/16824661/cors-request-not-working-in-safari but my angular app is on an S3 and the app servers are EC2s)

Mac dev center - https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/XHR.html - lists two other headers, which safari *is* sending in the request:
Access-Control-Request-Method
Access-Control-Request-Headers

I added them and now it is working!!!

So now my apache .htaccess has this 
Header always set Access-Control-Allow-Headers "X-Accept-Charset,X-Accept,Content-Type,Authorization,Accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers"

Rob Koberg

unread,
Jan 21, 2015, 12:50:40 PM1/21/15
to ang...@googlegroups.com
Spoke too soon. It is now working in my desktop with safari emulating the iOS8.1 user agent on the server, but not with a real ipad...

Jörg Zimmer

unread,
Jan 22, 2015, 4:05:37 AM1/22/15
to ang...@googlegroups.com

Hi Rob,

yes, unfortunately this isn't working any better...

Rob Koberg

unread,
Jan 23, 2015, 9:18:15 PM1/23/15
to ang...@googlegroups.com
I got a little farther, where it is now working in desktop safari in iOS emulation mode when using the server. I thought maybe canceling the preflight options request would do the trick, but still not working on iPad iOS8. The previous request was for JSON which triggers the preflight OPTIONS request. If you request text/plain (add Accepts header) and return text/plain it won't trigger the preflight request.

Tomorrow I think I will try straight jQuery.ajax to see if this is some kind of bug in Angular itself.

Jörg Zimmer

unread,
Jan 26, 2015, 4:51:33 AM1/26/15
to ang...@googlegroups.com
Hi Rob,

I'm curious to know if you were successful :)

Rob Koberg

unread,
Jan 26, 2015, 10:52:53 AM1/26/15
to ang...@googlegroups.com
I haven't tried yet.
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To unsubscribe from this group and stop receiving emails from it, send an

Jörg Zimmer

unread,
Jan 30, 2015, 3:19:13 AM1/30/15
to ang...@googlegroups.com
Hi Rob,

I tried myself yesterday but with no luck...
I added this on the client-side:

.config(function($httpProvider){
$httpProvider.defaults.headers.common['Content-Type'] = 'text/plain; charset=utf-8';
$httpProvider.defaults.headers.common.Accept = 'text/plain';
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

But still OPTIONS preflights...
I think that is because of the Authorization header I'm sending for my JWT...

Authorization is the reason not to switch to JSONP... 

Rob Koberg

unread,
Feb 3, 2015, 7:56:44 PM2/3/15
to ang...@googlegroups.com
I have this working now, but I had to use jQuery.ajax and not angular's own. Here is what works:


SessionCreator.$inject = ['$http', '$q', '$rootScope', '$timeout', 'ENV', 'User'];
function SessionCreator($http, $q, $rootScope, $timeout, ENV, User) {

var deferred = $q.defer();

jQuery.ajax(ENV.apiEndPoint + '/user-init', {

accepts: 'application/json',
dataType: 'json',
headers: {
Accept: 'application/json',
Authorization: User.getAuth()
},

success: function(data) {
      $rootScope.maintenance = false;
User.
init(data.user);
$rootScope.
totalReads = data.totalReads;

if (data.maintenance) {
$rootScope.
maintenance = true;
$rootScope.
maintenanceMsg = data.content;
}

deferred.resolve();
},
error: function(jqXHR, status, errorThrown) {
console.log('SessionCreator error jqXHR', jqXHR);
console.log('SessionCreator error status', status);
console.log('SessionCreator error errorThrown', errorThrown);

User.
init(data.user);
$rootScope.
totalReads = data.totalReads;
if (data.maintenance) {
$rootScope.
maintenance = true;
$rootScope.
maintenanceMsg = data.content;
}
jQuery('.loader-wrap').fadeOut();
$timeout(
function() {});

}
});

return deferred.promise;
}

This does not work:


SessionCreator.$inject = ['$http', '$q', '$rootScope', '$timeout', 'ENV', 'User'];
function SessionCreator($http, $q, $rootScope, $timeout, ENV, User) {

var deferred = $q.defer();

// used text here to try and avoid preflight request. Didn't work.
$http
.get(ENV.apiEndPoint + '/user-init',
{
responseType: 'text',
headers: {
Accept: 'text/plain'
}
}
)
.success(function(data) {
$rootScope.maintenance = false;
User.init(data.user);
$rootScope.totalReads = data.totalReads;

if (data.maintenance) {
$rootScope.maintenance = true;
$rootScope.maintenanceMsg = data.content;
}

deferred.resolve();
})
.error(function(data, status, headers, config) {
console.log('SessionCreator error data', data);
console.log('SessionCreator error status', status);
console.log('SessionCreator error headers', headers);
console.log('SessionCreator error config', config);

User.init(data.user);
$rootScope.totalReads = data.totalReads;
if (data.maintenance) {
$rootScope.maintenance = true;
$rootScope.maintenanceMsg = data.content;
}
jQuery('.loader-wrap').fadeOut();
$timeout(function() {});

});

return deferred.promise;
}

Jörg Zimmer

unread,
Feb 4, 2015, 4:42:39 AM2/4/15
to ang...@googlegroups.com
Hey Rob,

I think you will bang your head now, as I just did...
I also have it working just in this second... BUT: I just did some apache config:

Header always set Access-Control-Allow-Headers "Origin,X-Requested-With,Content-Type,Accept,Authorization,Accept-Language,Content-Language,Last-Event-ID,X-HTTP-Method-Override"
Header always set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS"
Header always set Access-Control-Allow-Credentials "true"
Header always set Cache-Control "max-age=0"

I added the Headers for credentials and cache-control plus the allow-headers entry for X-HTTP-Method-Override.
Don't know what exactly does the trick, but even the older Version of my angular-app now works on my iPhone with iOS8...

Will do some more testing, but I think this was it....

Samuel J. Choi

unread,
Mar 5, 2015, 6:15:16 PM3/5/15
to ang...@googlegroups.com
Hi Rob and Jorg,

It seems like I'm having related problems. 
Basically, I have a website built with angularJS which is meant to be mobile-friendly. The app basically makes one POST request to a JAVA server and I've been seeing a long lag upon a POST request on iOS Safari when testing on an iPad and on an iPhone. 
I am using the Angular $http call to make the POST request, which means just before the POST request, the app makes an OPTIONS preflight request. The JAVA server in accepts OPTIONS request and the app works without a problem in other browsers on pc (windows and Mac) as well as other Android devices. However, on the iPad and iPhone, the OPTIONS request takes anywhere from 8 seconds to 20 seconds. 

I found this thread because I was trying to find a solution to this problem and it seems like you have found a solution to your problem. If so, can you explain how you've solved the problem you are dealing with? I do understand that our problems may not be exactly the same but I'd like to understand how you've solved yours. 

Thanks,
Sam

u1_g...@dslr.net

unread,
Apr 20, 2015, 3:37:15 AM4/20/15
to ang...@googlegroups.com
Instead of putting a dozen headers in hoping to hit ones that are included,
have you tried just returning the ones that it sends in Access-Control-Request-Headers ?
That is the technique for replying to the Origin request... echo back what it wants.

I'm seeing a small percentage of IOS browsers on 8.1 on phone or ipad fail CORS POST requests after the OPTION request,
but it is only a small percentage, and I can't reproduce.

Rahul Sagore

unread,
Jan 13, 2016, 8:07:13 AM1/13/16
to AngularJS
I was also facing the CORS error in Safari 8.0.7. But on chrome it was showing "400: Bad request". The problem was with the request data I was sending. So corrected it from my side and it worked on safari.
So safari was displaying wrong error. It should be the "400: Bad request", rather than CORS. 

Yadvendar Champawat

unread,
Aug 31, 2016, 4:50:09 AM8/31/16
to AngularJS
Hi Rob and Jörg,
FYI
I was also facing a similar issue. Angularjs app calling the rest api server (different domain - CORS). All browsers were working fine except for Safari on iOS and OSX, that too only when Safari calls the API server on HTTPS. Safari calling API server on HTTP worked fine. It was not an angular specific issue as jquery ajax implementation also reproduced the issue. Finally, the response header - "Connection": "close" was removed( connections were kept alive), it started working for Safari with HTTPS.

Regards,
Yadvendar
Reply all
Reply to author
Forward
0 new messages