After not being able to figure out what was going wrong, I thought that I'd try my luck on here to see if anyone knows what's going on.
I have an angularJS app with a GoLang/Gorilla mux server backend.
The web app is on http://localhost:8888/ and the server, http://localhost:8080/
Basically I have this simple Javascript GET request:
$.get('http://localhost:8080/api/v1'+'/locations/', {borough: "Queens"})
Using inspect element, in the response headers I can see the following:
Content-Length:68
Content-Type:text/html; charset=utf-8
Date:Sun, 17 Apr 2016 20:12:00 GMT
Location:/api/v1/locations?borough=queens
And the following in the console:
XMLHttpRequest cannot load http://localhost:8080/api/v1/locations/? borough=queens. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8888' is therefore not allowed access.
I try the exact same request using Postman and see a 401 with:
Access-Control-Allow-Origin →*
Content-Length →0
Content-Type →text/plain; charset=utf-8
Date →Sun, 17 Apr 2016 19:46:53 GMT
Which is what I expect. For some reason, it appears that my request is not even making it to the server, which does not offer a 301 request. The fact that Postman and the app give completely different responses is perplexing.
I had some issues with CORS but thought I resolved that. The fact that Postman gives me a different result with the Access-Control-Allow-Origin header makes me think this is something else.
I welcome any help.
Edit:
I made the server reply back with the standard Cors parameters. This is what I get now from Postman:
Access-Control-Allow-Headers →Origin, X-Requested-With, Content-Type, Accept, Authorization
Access-Control-Allow-Methods →GET, POST, PUT, DELETE
Access-Control-Allow-Origin →*
Content-Length →0
Content-Type →text/plain; charset=utf-8
Date →Sun, 17 Apr 2016 20:27:31 GMT
Still get the 301 for the JS call...
Edit2: (tried setting Postman call to exact same as network request)
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:8080
Origin:http://localhost:8888
Referer:http://localhost:8888/root/mainapp/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Still get the same 301 from inspect element and expected 401 with Postman. How can it be that in a Restful HTTP context, we have two identical HTTP calls and yet have completely different behavior out of it?!
So basically when I removed the final slash to make it:
from
$.get('http://localhost:8080/api/v1'+'/locations/', {borough: "Queens"})
to
$.get('http://localhost:8080/api/v1'+'/locations', {borough: "Queens"})
This worked!!! I have no bloody idea as to why. If I would love to hear from anyone that may know what happened here and why this works. I'll reiterate- because of the last slash, the request didn't even make it to the server.
Related
I am trying to understand how the whole CORS policy works. To explain my confusion, let me give you an example:
$.get("https://www.google.com", function(response) { alert(response) });
The above request will return with the following error:
XMLHttpRequest cannot load https://www.google.com/. Redirect from 'https://www.google.com/' to 'https://www.google.ca/?gfe_rd=cr&ei=TlqUWeGEH5HRXqW6utgI' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://fiddle.jshell.net' is therefore not allowed access.
Now in order for that to work, google would have to white-list https://fiddle.jshell.net.
Now, if I were to try the same thing on a restful API page, that will work. My question is really simple, Why?
Trying to analyze this, I tried hitting an API and analyzing its response:
https://apigee.com/console/bing?req=%7B%22resource%22%3A%22web_search%22%2C%22params%22%3A%7B%22query%22%3A%7B%22query%22%3A%22sushi%22%2C%22sources%22%3A%22web%22%7D%2C%22template%22%3A%7B%22format%22%3A%22json%22%7D%2C%22headers%22%3A%7B%7D%2C%22body%22%3A%7B%22attachmentFormat%22%3A%22mime%22%2C%22attachmentContentDisposition%22%3A%22form-data%22%7D%7D%2C%22verb%22%3A%22get%22%7D
Response:
HTTP/1.1 200
Date:
Wed, 16 Aug 2017 14:31:32 GMT
Content-Length: 266
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Server: Apigee Router
X-Content-Type-Options: nosniff
I came to conclusion that it must be the headers. Specifically I belive that it is this header: Content-Type: application/json; But I don't know for sure, I am trying to understand this and hoping somebody here can explain to me.
So I did 2 tests: running your code $.get("https://www.google.com", function(response) { alert(response) }); snippet from the console and requesting https://www.google.com from https://apigee.com/console/others
I think what happens in the 1st case is the fact that the request is done from the client, next request headers are sent:
:authority:www.google.com
:method:GET
:path:/?_=1502896196820
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, br
accept-language:en-US,en;q=0.8
origin:https://stackoverflow.com
referer:https://stackoverflow.com/questions/45717044/understanding-page-response
user-agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3187.0 Safari/537.36
x-chrome-uma-enabled:1
x-client-data:CJG2yQEIo7bJAQiMmMoBCKudygEIs53KAQjRncoBCKiiygE=
Since Google does not reply with 'Access-Control-Allow-Origin: *' - client, and in the request I have origin:https://stackoverflow.com, Chrome in my case throws CORS error.
In the 2nd test, using https://apigee.com/console/others and requesting https://www.google.com , apigee.com seems to overwrite headers and sends:
GET / HTTP/1.1
Host:
www.google.com
X-Target-URI:
https://www.google.com
Connection:
Keep-Alive
Also, from DEV console, I can see it does server to server call so no client involved in throwing CORS, thus I am getting the responses with Google page.
UPDATE:
Regarding JSON API requests, here is some interesting info from Google CloudPlatform about CORS
Note: CORS configuration applies only to XML API requests. For JSON
API requests, Cloud Storage returns the Access-Control-Allow-Origin
header with the origin of the request.
Thus, if the request is performed from the client, a client should not throw CORS errors since it gets Access-Control-Allow-Origin with the same origin it sent.
However, different APIs and clients might process requests differently. Thus, sometimes Firefox throws CORS while Chrome does not.
I have enable Access-Control-Allow-Origin on my apache webserver. I am able to load all requests on the first load. However, subsequent loading/refreshing of the pages would leave half of the requests failed, leaving an error of,
XMLHttpRequest cannot load http://***. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
In Chrome Developer Tool, under the Network tab, enabling "Disable Cache" removes this error.
I am using AngularJS $http to call my request, I have changed the cache option to true/false but this abnormality persist. For your information, I am also using an angular-cache module, https://github.com/jmdobry/angular-cache, I have tried enabling/disabling this too, but to no avail.
Here is a copy of the request header:
GET ***Valid_Url_With_Parameters** HTTP/1.1
Host: ********
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
I have a 2 different types response header with different HTTP status codes for the failed requests.
HTTP/1.1 200 OK
Content-Length: 564121
Content-Type: application/json
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Last-Modified: Fri, 16 Sep 2016 12:41:41 GMT
Connection: keep-alive
Date: Fri, 16 Sep 2016 12:43:44 GMT
HTTP/1.1 206 Partial Content
Content-Type: application/json
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Last-Modified: Fri, 16 Sep 2016 13:39:05 GMT
Content-Range: bytes 29200-29200/785592
Content-Length: 1
Connection: keep-alive
Date: Fri, 16 Sep 2016 14:20:48 GMT
It seems something to do with caching. The first time the page loads, all of the request have the correct access control header. Subsequent refresh/reload removes this header. How can I continue using caching and keep the access control header?
Edit:
Just to add on, I tried using Safari, the same abnormality appeared. It load on the first try but subsequent loading will throw a no access control allow origin error. However, this time, the response header in Safari shows blank.
Edit 2:
Abnormality appears in Firefox as well but not in Opera Beta version 40.0.2308.52. I am beginning to wonder if this is the cause of the browser. Access-Control-Allow-Origin header is present too.
Response Header in Opera
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Sat, 17 Sep 2016 06:56:53 GMT
Server: Apache/2.2.15 (CentOS)
Vary: Accept
Transfer-Encoding: chunked
Edit 3:
I would like to add that the requests that I'm pulling is a large amount of data. I am pulling the last 7 days history of data, there are about 20 JSON files, each ranging from 500KB to 1000KB. I noticed that when I change the query parameter to pull in a small history of data, this error does not happen.
Any help is much appreciated.
One work around I've found is to dynamically generate a javascript file on the server as resource included into your page. This doesn't require AJAX the which gets blocked by CORS and can be cached.
We had this same problem in Chrome when returning a specific value in the 'Access-Control-Allow-Origin' header. We were able to solve it by also including Vary: Origin in the response headers.
It appears Chrome considers response headers, including 'Access-Control-Allow-Origin', as part of the cached response. So if it requests the same file from a different origin, that header from the cache will not match. But if you include Vary: Origin it lets Chrome know the response (just this one header in our case) will be different based on the Origin of the request.
This page on MDN explains it:
If the server sends a response with an Access-Control-Allow-Origin
value that is an explicit origin (rather than the "*" wildcard), then
the response should also include a Vary response header with the value
Origin — to indicate to browsers that server responses can differ
based on the value of the Origin request header.
I would recommend you to add chrome extension in your browser
Allow-Control-Allow-Origin: *
I'm facing a rather sudden Google Maps Geocoding issue. It was all working fine till yesterday but since then I've been getting a CORS error on any request made to their Geocoding API.
My request:
https://maps.googleapis.com/maps/api/geocode/json?latlng=18.92187618976372,72.82581567764282&key=<API_KEY>
My request headers:
Provisional headers are shown
Accept:application/json, text/plain, */*
Origin:http://domain
Referer:http://domain/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36
X-FirePHP-Version:0.0.6
Response headers:
access-control-allow-origin:*
alternate-protocol:443:quic,p=1
cache-control:public, max-age=86400
content-encoding:gzip
content-length:1279
content-type:application/json; charset=UTF-8
date:Thu, 23 Jul 2015 09:50:49 GMT
expires:Fri, 24 Jul 2015 09:50:49 GMT
server:mafe
status:200
vary:Accept-Language
x-frame-options:SAMEORIGIN
x-xss-protection:1; mode=block
Error message:
XMLHttpRequest cannot load https://maps.googleapis.com/maps/api/geocode/json?latlng=18.92187618976372,72.82581567764282&key=<API_KEY>. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://domain' is therefore not allowed access.
Setting the header to null worked for me.
let url= `https://maps.googleapis.com/maps/api/geocode/json?latlng=${payload.lat},${payload.lng}&key=${process.env.NEXT_PUBLIC_GOOGLE_MAP}`;
const res = await axios.get(url,{headers:null});
My system was setup in such a way that I have my front end is being served from a cross domain from my logic server. For this, I had set my withCredentials flag as true. Since Maps' API uses a * wildcard, withCredentials was giving an error.
To solve this, I used a separate XHR method for Maps calls where the flag was set as false.
Hello so i'm trying to call my backend and getting some strange issue with calling post method.
Remote Address:192.168.58.183:80
Request URL:http://192.168.58.183/ESService/ESService.svc/CreateNewAccount
Request Method:OPTIONS
Status Code:405 Method Not Allowed
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,pl;q=0.6
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:192.168.58.183
Origin:http://localhost:8100
Referer:http://localhost:8100/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) > AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93
Safari/537.36
Response Headersview source
Access-Control-Allow-Headers:Content-Type, Accept
Access-Control-Allow-Methods:POST,GET,OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Allow:POST
Content-Length:1565
Content-Type:text/html; charset=UTF-8
Date:Mon, 02 Feb 2015 09:11:17 GMT
Server:Microsoft-IIS/7.5
X-Powered-By:ASP.NET
And my code looks like here i think this call is okay can someone review it?
$scope.RegisterUser = function(){
var us = {
UserName:$scope.userName,
Password:$scope.password,
UserRoleID:null,
Company:$scope.company,
Terms:$scope.terms,
ID:null,
BuyerID:app.buyerId
};
$http({method:'POST', url:app.wcf + '/CreateNewAccount', data:{us:us}})
.then(
function(resp){
app.Logger(resp.data);
},
function(err){
app.Logger(err);
})};
So maybe i'm doing something wrong or i need to pass optional config to http?
Normally, browsers will not allow your site's JavaScript to read the data from a cross-origin request. This is because your site might be instructing the browser to get information from the user's online banking, company intranet, or some other private site. This is called The Same Origin Policy.
A standard called CORS allows a site to give permission to another site to read data from it.
Since POST requests can have side effects, an additional layer of security is added. Before the browser will make the POST request, it will make a pre-flight OPTIONS request to ask for permission to make the POST request.
Your server is not configured to handle that OPTIONS request (and probably isn't configured to return the CORS headers for the POST request either).
You need to set up CORS support if you want to allow your JavaScript to make requests to it from a different origin.
This is a pre flight request and is used to enable CORS there is no need to be concerned this is normal.
I'm feeling completely stupid because I've spent two hours solving task which should be very simple and which I solved many times before. But now I'm not even sure in which direction to dig.
I fail to fetch static content using ajax from local servers (Apache and Mongrel). I get responses 200 and 206 (depending on the server), empty response text (although Content-Length header is always correct), firebug shows request in red.
Javascript is very generic, I'm getting same results even here: http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_first
(just change document location to 'http://localhost:3000/whatever')
So, it's probably not the cause.
Well, now I'm out of ideas. I can also post http headers, if it'll help.
Thanks!
Response Headers
Connection close
Date Sat, 01 May 2010 21:05:23 GMT
Last-Modified Sun, 18 Apr 2010 19:33:26 GMT
Content-Type text/html
Content-Length 7466
Request Headers
Host localhost:3000
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Referer http://www.w3schools.com/ajax/tryit_view.asp
Origin http://www.w3schools.com
Response Headers
Date Sat, 01 May 2010 21:54:59 GMT
Server Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8l DAV/2 mod_jk/1.2.28
Etag "3d5cbdb-fb4-4819c460d4a40"
Accept-Ranges bytes
Content-Length 4020
Cache-Control max-age=7200, public, proxy-revalidate
Expires Sat, 01 May 2010 23:54:59 GMT
Content-Range bytes 0-4019/4020
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type application/javascript
Request Headers
Host localhost
User-Agent Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 115
Connection keep-alive
Origin null
UPDATED:
I've found a problem, it was about cross-domain requests. I knew that there are restrictions, but thought they're relaxed for local filesystem and local servers. (and expected more descriptive error message, anyway)
Thanks everybody!
It seems lake a caching problem only. Just delete cache inside of Internet Explorer and repeat your experiment. All HTTP GET requests will be cached. IE cache also ajax responses. If you don't like it you can append the URL with the text like '?p=blala'. Where 'p' is a name which will be interpret as a name of a parameter and text 'blala' must be unique in every request. Typically one use (new Date).getTime() construct to generate such 'blala'. IE will "think", that URL is new and will always send request to server.
UPDATED: Caching of static data will be made in all browsers, especially if Web server explicitly allow this: see Cache-Control: max-age=7200, public, proxy-revalidate is the response from server. Just try to go to http://www.w3schools.com/ajax/tryit.asp?filename=tryajax_first and modify the line
xmlhttp.open("GET","ajax_info.txt",true);
to
xmlhttp.open("GET","ajax_info.txt?p=" + (new Date).getTime(),true);
then click on "Edit and Click Me >>". Then if you click on "Change Content" button you will see in the HTTP traffic full data contain. I don't see any time 206 code. What it means if Response has "Accept-Ranges: bytes" and "Content-Range" like "bytes 0-4019/4020" inside of HTTP header you can read on http://benramsey.com/archives/206-partial-content-and-range-requests/