I have encountered a problem that I cant resolve.
I have some js (jquery) POST soap (over PHP) request code working on Apache with Cors enabled for calling HTTPS, and it worked fine.
I've migrated to IIS7, set response headers:
Access-Control-Allow-Origin = *
Access-Control-Allow-Methods = POST`
and now strangly when sending
Content-Type: text/xml;
it is refused, but when sending a default
application/x-www-form-urlencoded
strangly I got the response (of course error response from Soap server but still, meaning that Cors works for this).
So the question is, if there is anything else to set in iis headers? I tried to find an answer for a day but with no luck. My guess is it is about Access-Control-Allow-Headers but still I cant find a valid example.
You need to set the following header:
Access-Control-Allow-Headers: Content-Type
You may also have to put other headers in that list. The best way to figure out which headers to add is to inspect the Access-Control-Request-Headers header on the request, and see what values its asking for, and then echo those values in the response above.
The reason Content-Type needs to be included in this header is because you are asking for a non-standard value ('application/x-www-form-urlencoded' is a standard value).
Related
I created an API endpoint using Google Cloud Functions and am trying to call it from a JS fetch function.
I am running into errors that I am pretty sure are related to either CORS or the output format, but I'm not really sure what is going on. A few other SO questions are similar, and helped me realize I needed to remove the mode: "no-cors". Most mention enabling CORS on the BE, so I added response.headers.set('Access-Control-Allow-Origin', '*') - which I learned of in this article - to ensure CORS would be enabled... But I still get the "Failed to fetch" error.
The Full Errors (reproducible in the live demo linked below) are:
Uncaught Error: Cannot add node 1 because a node with that id is
already in the Store. (This one is probably unrelated?)
Access to fetch at
'https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=37.75&lon=-122.5'
from origin 'https://o2gxx.csb.app' has been blocked by CORS policy:
Request header field access-control-allow-origin is not allowed by
Access-Control-Allow-Headers in preflight response.
GET
https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=37.75&lon=-122.5 net::ERR_FAILED
Uncaught (in promise) TypeError: Failed to fetch
See Code Snippets below, please note where I used <---- *** Message *** to denote parts of the code that have recently changed, giving me one of those two errors.
Front End Code:
function getCSC() {
let lat = 37.75;
let lng = -122.5;
fetch(
`https://us-central1-stargazr-ncc-2893.cloudfunctions.net/nearest_csc?lat=${lat}&lon=${lng}`,
{
method: "GET",
// mode: "no-cors", <---- **Uncommenting this predictably gets rid of CORS error but returns a Opaque object which seems to have no data**
headers: {
// Accept: "application/json", <---- **Originally BE returned stringified json. Not sure if I should be returning it as something else or if this is still needed**
Origin: "https://lget3.csb.app",
"Access-Control-Allow-Origin": "*"
}
}
)
.then(response => {
console.log(response);
console.log(response.json());
});
}
Back End Code:
import json
import math
import os
import flask
def nearest_csc(request):
"""
args: request object w/ args for lat/lon
returns: String, either with json representation of nearest site information or an error message
"""
lat = request.args.get('lat', type = float)
lon = request.args.get('lon', type = float)
# Get list of all csc site locations
with open(file_path, 'r') as f:
data = json.load(f)
nearby_csc = []
# Removed from snippet for clarity:
# populate nearby_csc (list) with sites (dictionaries) as elems
# Determine which site is the closest, assigned to var 'closest_site'
# Grab site url and return site data if within 100 km
if dist_km < 100:
closest_site['dist_km'] = dist_km
// return json.dumps(closest_site) <--- **Original return statement. Added 4 lines below in an attempt to get CORS set up, but did not seem to work**
response = flask.jsonify(closest_site)
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Methods', 'GET, POST')
return response
return "No sites found within 100 km"
Fuller context for code snippets above:
Here is a Code Sandbox Demo of the above.
Here is the full BE code on GitHub, minus the most recent attempt at adding CORS.
The API endpoint.
I'm also wondering if it's possible that CodeSandbox does CORS in a weird way, but have had the same issue running it on localhost:3000, and of course in prod would have this on my own personal domain.
The Error would appear to be CORS-related ( 'https://o2gxx.csb.app' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.) but I thought adding response.headers.set('Access-Control-Allow-Origin', '*') would solve that. Do I need to change something else on the BE? On the FE?
TLDR;
I am getting the Errors "Failed to fetch" and "field access-control-allow-origin is not allowed by Access-Control-Allow-Headers" even after attempts to enable CORS on backend and add headers to FE. See the links above for live demo of code.
Drop the part of your frontend code that adds a Access-Control-Allow-Origin header.
Never add Access-Control-Allow-Origin as a request header in your frontend code.
The only effect that’ll ever have is a negative one: it’ll cause browsers to do CORS preflight OPTIONS requests even in cases when the actual (GET, POST, etc.) request from your frontend code would otherwise not trigger a preflight. And then the preflight will fail with this message:
Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response
…that is, it’ll fail with that unless the server the request is being made to has been configured to send an Access-Control-Allow-Headers: Access-Control-Allow-Origin response header.
But you never want Access-Control-Allow-Origin in the Access-Control-Allow-Headers response-header value. If that ends up making things work, you’re actually just fixing the wrong problem. Because the real fix is: never set Access-Control-Allow-Origin as a request header.
Intuitively, it may seem logical to look at it as “I’ve set Access-Control-Allow-Origin both in the request and in the response, so that should be better than just having it in the response” — but it’s actually worse than only setting it in the response (for the reasons described above).
So the bottom line: Access-Control-Allow-Origin is solely a response header, not a request header. You only ever want to set it in server-side response code, not frontend JavaScript code.
The code in the question was also trying to add an Origin header. You also never want to try to set that header in your frontend JavaScript code.
Unlike the case with the Access-Control-Allow-Origin header, Origin is actually a request header — but it’s a special header that’s controlled completely by browsers, and browsers won’t ever allow your frontend JavaScript code to set it. So don’t ever try to.
I use the Javascript API within an Angular Project. I'm using HTTPS connection. It all worked the last months but since last week, I don't get any Tiles loaded.
To a lot of requests, I get the response:
403 "No Access-Control-Allow-Origin header is present on the requested resource."
Sometimes the request is successful and I get a Tile and the correct cors header, but that is only 1 of 20 requests I think.
Did I miss some API changes? Is this only on my side or are there any others affected?
You can always Enable CORS by returning correct headers
Access-Control-Allow-Headers string
Access-Control-Allow-Methods string
Access-Control-Allow-Origin string
For more details -
https://developer.here.com/documentation/tour-planning/api-reference-swagger.html
https://developer.here.com/olp/documentation/vector-tiles-api/dev_guide/topics/http-response-codes.html
I am attempting to retrieve a class (with GET) from Parse using a client key. I was able to send a successful request using Advanced Rest Client for Google Chrome; I used X-Parse-Application-Id and X-Parse-Client-Key headers.
[edit] [edit2]
Response headers (obtained from Chrome Developer Tools OPTIONS):
HTTP/1.1 200 OK
Access-Control-Allow-Headers: X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type
Access-Control-Allow-Methods: OPTIONS, POST, GET, PUT, DELETE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 86400
Content-Type: application/json; charset=utf-8
Date: Sun, 29 Nov 2015 04:23:08 GMT
Server: nginx/1.6.0
X-Parse-Platform: G1
X-Runtime: 0.000118
Content-Length: 0
Connection: keep-alive
However, attempting to do the same in an Angular app gives me the following error:
XMLHttpRequest cannot load https://api.parse.com/1/classes/GenResources. Request header field X-Parse-Client-Key is not allowed by Access-Control-Allow-Headers in preflight response.
Parse says it supports using cross-origin resource sharing, and I was able to make the request earlier using a different client so I'm pretty sure the server isn't the issue. I wouldn't be able to modify what the response header is anyways.
Here's the code I used to form the GET request.
var ng_portal = angular.module("ngPortal", []);
ng_portal.controller("GenResourcesCtrl", ["$http", function($http) {
$http({
method: "GET",
url: PARSE_URL + "/1/classes/GenResources",
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": PARSE_APP_ID,
"X-Parse-Client-Key": PARSE_CLIENT_KEY
}
}).then(
function success(res) {
console.log(res);
},
function error(res) {
console.log(res);
}
);
}]);
You are setting custom headers in the request, which will trigger a pre-flight (OPTIONS) request. The response from that request must include a header called "access-control-allow-headers" with the value being a list of the headers you are trying to set.
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
specifically the section on pre-flight requests.
I suggest using the browser developer tools to look at the headers of the requests and responses to see if they conform to the CORS spec. From the error message you provided, it looks like the server hosting the cross domain call you are making, does not support custom headers. If you see otherwise, please update your question with the headers and I can provide more help.
This seems to be an issue with Parse.com actually. After exactly one frustrated hour, I came across this Google Groups post
Relevant quote
From my testing, this never ( client or javascript key) worked via javascript rest interactions through the browser.
I actually created a Parse Bug on this:
https://developers.facebook.com/bugs/488204124680438
Because I thought both of those keys should work through the browser ( WITHOUT NEEDING TO USE A SDK ).
I’d suggest reading reading my bug. I still think the the correct implementation is to enable these keys to work properly with browser requests because it works if you do it outside the browser.
But alas, they don’t seem to get the issue, or don’t understand why disabling it only in the browser doesn’t make sense since you can use it on any other platform without issues. Just… Doesn’t… Make… Sense.
I instead used my JavaScript Key X-Parse-Javascript-Key (which, according to the docs as of today, only works with their JavaScript SDK) and it works fine as a drop-in replacement for X-Parse-Client-Key
I'm currently trying a DELETE type of request with Angular ngResource on a Restful API located on another domain.
GET and PUT work fine.
DELETE works in the Advanced Rest Client Chrome extension but doesn't work when tried with Angular $resource.
I have noticed a difference in the headers sent, which are these two:
Access-Control-Request-Headers:accept
Access-Control-Request-Method:DELETE
When I try to add these two headers in Advanced Rest Client I get the following errors in the Chrome console:
Refused to set unsafe header "Access-Control-Request-Headers"
Refused to set unsafe header "Access-Control-Request-Method"
Finally the server (which is normally configured to accept cross-domain requests), when I try the DELETE request with Angular, sends the following response (with status 200 and method use OPTIONS):
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:*
Access-Control-Allow-Origin:*
Allow:PUT,DELETE
Cache-Control:private, must-revalidate
Connection:close
Content-Length:0
Content-Type:text/html; charset=UTF-8
Date:Thu, 12 Feb 2015 12:08:47 GMT
ETag:"d41d8cd98f00b204e9800998ecf8427e"
Server:Apache/2.2.29 (Unix) mod_ssl/2.2.29 OpenSSL/0.9.8o DAV/2 PHP/5.5.20
But I get the error:
XMLHttpRequest cannot load [URL]. Method DELETE is not allowed by Access-Control-Allow-Methods.
I suspect the first mentioned two headers to be the cause of the problem. Are they the problem and if yes how could I remove them?
If it can help, I tried configuring my $httpProvider (as seen in other questions/answers) and it currently looks like this:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
delete $httpProvider.defaults.headers.common['Access-Control-Request-Method'];
delete $httpProvider.defaults.headers.common['Access-Control-Request-Headers'];
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
Your server should set Access-Control-Allow-Methods header for response instead of Allow header like:
Access-Control-Allow-Methods:PUT,DELETE
A simple GET request with no custom headers. The response is returned as expected. The data in the body is accessible, but not the headers.
When I try to access the "etag" header, browsers raise an exception :
Refused to get unsafe header "etag"
Chrome, Safari and Firefox all behave the same. I didn't test it on IE.
What am I missing here?
Only simple response headers are exposed when using CORS. Simple response headers are defined here. ETag is not a simple response headers. If you want to expose non-simple headers, you need to set the Access-Control-Expose-Headers header, like so:
Access-Control-Expose-Headers: ETag
However, note that I've noticed bugs in Chrome, Safari and Firefox that prevent non-simple headers from being exposed correctly. This may be fixed by now, I'm not sure.
You shouldn't need to do a preflight request, since preflight is only required for non-GET/POST http methods or non-simple request headers (and you are asking about response headers).
Have you ever tried AJAX 2.0 (Cross domain sharing) is a methodology fairly recently brought out by W3C: http://www.w3.org/TR/XMLHttpRequest2/#ref-cors
Also there is another way of doing this, which is called JSON-P, it's like a JSON request, but you can use it for cross-domains: http://en.wikipedia.org/wiki/JSONP
Both can be very dangerous to the site owners if not setup correctly though. So do be careful when using it.
[PS]
Not sure if this will help : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html