axios preflight fail error 301 using vue.js - vue.js

I've got a Laravel 5.4 API, that works fine in Postman and the Browser. Localhost works fine- Laravel 5.4 is running on one port, and Vue in hot deploy mode is running fine.
However, when I move the Vue code to my production server I get this error:
Response for preflight is invalid (redirect)
In Chrome Developer Tools, the network tab shows this:
General
Request URL:http://backend-dev.xolas.io/api/v1/view/calendar/-30/90/
Request Method:OPTIONS
Status Code:301 Moved Permanently
Remote Address:217.182.66.247:80
Referrer Policy:no-referrer-when-downgrade
Response Headers
Connection:Keep-Alive
Content-Length:349
Content-Type:text/html; charset=iso-8859-1
Date:Mon, 10 Jul 2017 13:40:08 GMT
Keep-Alive:timeout=5, max=100
Location:http://backend-dev.xolas.io/api/v1/view/calendar/-30/90
Server:Apache/2.4.25 (Ubuntu)
Origin Headers
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:access-control-allow-origin,authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:backend-dev.xolas.io
Origin:http://localhost:8080
Referer:http://localhost:8080/
User-Agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.109 Mobile Safari/537.36
I've installed a CORS plugin on Laravel, still no joy.
My axios config is as follows:
axios.defaults.headers.common['Authorization'] = store.apiKey
axios.defaults.headers.get['Content-Type'] = 'application/json;charset=utf-8'
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8'
axios.defaults.headers.common['Access-Control-Allow-Origin'] = 'https://' + store.endpoint + ', http://' + store.endpoint
Endpoint is Larvel API server, which works fine.
Any clues would help, since I'm at a loss on how to resolve this. Thanks in advance.

The server is is sending a redirect from:
http://backend-dev.xolas.io/api/v1/view/calendar/-30/90/
to:
http://backend-dev.xolas.io/api/v1/view/calendar/-30/90
Removing the trailing '/' in your request should prevent the 301. (Although that url is responding with a 500 Server Error.

Your browser’s sending a CORS preflight OPTIONS request before trying whatever request it is that your code’s actually trying to send itself, and then your Laravel backend is responding to that OPTIONS request with a 301 Moved Permanently redirect.
The server must respond to the OPTIONS preflight with a 2xx status — typically 200 or 204.
If the server doesn’t do that, the preflight fails and the browser never tries the actual request.
So you must change your Laravel backend to respond to that OPTIONS with a 200 or 204.
And the browser does a preflight to begin with because your request adds Authorization and Content-Type: application/json;charset=utf-8 & Access-Control-Allow-Origin headers.
You should remove the code that’s adding the Access-Control-Allow-Origin there, because that’s a response header and there’s never any need to send it in a request. But assuming you need the Authorization and Content-Type headers in the request in order for it to actually work as expected with your backend, then there’s no way you can avoid the browser preflight.
So you really must configure your Laravel backend to respond to OPTIONS with a 2xx success.

Related

Can't use swagger ui in chrome and intellij idea due to CORS [duplicate]

Apparently, I have completely misunderstood its semantics. I thought of something like this:
A client downloads JavaScript code MyCode.js from http://siteA - the origin.
The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB, which I thought meant that MyCode.js was allowed to make cross-origin references to the site B.
The client triggers some functionality of MyCode.js, which in turn make requests to http://siteB, which should be fine, despite being cross-origin requests.
Well, I am wrong. It does not work like this at all. So, I have read Cross-origin resource sharing and attempted to read Cross-Origin Resource Sharing in w3c recommendation.
One thing is sure - I still do not understand how I am supposed to use this header.
I have full control of both site A and site B. How do I enable the JavaScript code downloaded from the site A to access resources on the site B using this header?
P.S.: I do not want to utilize JSONP.
Access-Control-Allow-Origin is a CORS (cross-origin resource sharing) header.
When Site A tries to fetch content from Site B, Site B can send an Access-Control-Allow-Origin response header to tell the browser that the content of this page is accessible to certain origins. (An origin is a domain, plus a scheme and port number.) By default, Site B's pages are not accessible to any other origin; using the Access-Control-Allow-Origin header opens a door for cross-origin access by specific requesting origins.
For each resource/page that Site B wants to make accessible to Site A, Site B should serve its pages with the response header:
Access-Control-Allow-Origin: http://siteA.com
Modern browsers will not block cross-domain requests outright. If Site A requests a page from Site B, the browser will actually fetch the requested page on the network level and check if the response headers list Site A as a permitted requester domain. If Site B has not indicated that Site A is allowed to access this page, the browser will trigger the XMLHttpRequest's error event and deny the response data to the requesting JavaScript code.
Non-simple requests
What happens on the network level can be slightly more complex than explained above. If the request is a "non-simple" request, the browser first sends a data-less "preflight" OPTIONS request, to verify that the server will accept the request. A request is non-simple when either (or both):
using an HTTP verb other than GET or POST (e.g. PUT, DELETE)
using non-simple request headers; the only simple requests headers are:
Accept
Accept-Language
Content-Language
Content-Type (this is only simple when its value is application/x-www-form-urlencoded, multipart/form-data, or text/plain)
If the server responds to the OPTIONS preflight with appropriate response headers (Access-Control-Allow-Headers for non-simple headers, Access-Control-Allow-Methods for non-simple verbs) that match the non-simple verb and/or non-simple headers, then the browser sends the actual request.
Supposing that Site A wants to send a PUT request for /somePage, with a non-simple Content-Type value of application/json, the browser would first send a preflight request:
OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Note that Access-Control-Request-Method and Access-Control-Request-Headers are added by the browser automatically; you do not need to add them. This OPTIONS preflight gets the successful response headers:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
When sending the actual request (after preflight is done), the behavior is identical to how a simple request is handled. In other words, a non-simple request whose preflight is successful is treated the same as a simple request (i.e., the server must still send Access-Control-Allow-Origin again for the actual response).
The browsers sends the actual request:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" }
And the server sends back an Access-Control-Allow-Origin, just as it would for a simple request:
Access-Control-Allow-Origin: http://siteA.com
See Understanding XMLHttpRequest over CORS for a little more information about non-simple requests.
Cross-Origin Resource Sharing - CORS (A.K.A. Cross-Domain AJAX request) is an issue that most web developers might encounter, according to Same-Origin-Policy, browsers restrict client JavaScript in a security sandbox, usually JS cannot directly communicate with a remote server from a different domain. In the past developers created many tricky ways to achieve Cross-Domain resource request, most commonly using ways are:
Use Flash/Silverlight or server side as a "proxy" to communicate
with remote.
JSON With Padding (JSONP).
Embeds remote server in an iframe and communicate through fragment or window.name, refer here.
Those tricky ways have more or less some issues, for example JSONP might result in security hole if developers simply "eval" it, and #3 above, although it works, both domains should build strict contract between each other, it neither flexible nor elegant IMHO:)
W3C had introduced Cross-Origin Resource Sharing (CORS) as a standard solution to provide a safe, flexible and a recommended standard way to solve this issue.
The Mechanism
From a high level we can simply deem CORS as a contract between client AJAX call from domain A and a page hosted on domain B, a typical Cross-Origin request/response would be:
DomainA AJAX request headers
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
DomainB response headers
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
The blue parts I marked above were the kernal facts, "Origin" request header "indicates where the cross-origin request or preflight request originates from", the "Access-Control-Allow-Origin" response header indicates this page allows remote request from DomainA (if the value is * indicate allows remote requests from any domain).
As I mentioned above, W3 recommended browser to implement a "preflight request" before submiting the actually Cross-Origin HTTP request, in a nutshell it is an HTTP OPTIONS request:
OPTIONS DomainB.com/foo.aspx HTTP/1.1
If foo.aspx supports OPTIONS HTTP verb, it might return response like below:
HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json
Only if the response contains "Access-Control-Allow-Origin" AND its value is "*" or contain the domain who submitted the CORS request, by satisfying this mandtory condition browser will submit the actual Cross-Domain request, and cache the result in "Preflight-Result-Cache".
I blogged about CORS three years ago: AJAX Cross-Origin HTTP request
According to this Mozilla Developer Network article,
A resource makes a cross-origin HTTP request when it requests a resource from a different domain, or port than the one which the first resource itself serves.
An HTML page served from http://domain-a.com makes an <img> src request for http://domain-b.com/image.jpg.
Many pages on the web today load resources like CSS style sheets, images and scripts from separate domains (thus it should be cool).
Same-Origin Policy
For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts.
For example, XMLHttpRequest and Fetch follow the same-origin policy.
So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.
Cross-Origin Resource Sharing (CORS)
To improve web applications, developers asked browser vendors to allow cross-domain requests.
The Cross-origin resource sharing (CORS) mechanism gives web servers cross-domain access controls, which enable secure cross-domain data transfers.
Modern browsers use CORS in an API container - such as XMLHttpRequest or fetch - to mitigate risks of cross-origin HTTP requests.
How CORS works (Access-Control-Allow-Origin header)
Wikipedia:
The CORS standard describes new HTTP headers which provide browsers and servers a way to request remote URLs only when they have permission.
Although some validation and authorization can be performed by the server, it is generally the browser's responsibility to support these headers and honor the restrictions they impose.
Example
The browser sends the OPTIONS request with an Origin HTTP header.
The value of this header is the domain that served the parent page. When a page from http://www.example.com attempts to access a user's data in service.example.com, the following request header would be sent to service.example.com:
Origin: http://www.example.com
The server at service.example.com may respond with:
An Access-Control-Allow-Origin (ACAO) header in its response indicating which origin sites are allowed.
For example:
Access-Control-Allow-Origin: http://www.example.com
An error page if the server does not allow the cross-origin request
An Access-Control-Allow-Origin (ACAO) header with a wildcard that allows all domains:
Access-Control-Allow-Origin: *
Whenever I start thinking about CORS, my intuition about which site hosts the headers is incorrect, just as you described in your question. For me, it helps to think about the purpose of the same-origin policy.
The purpose of the same-origin policy is to protect you from malicious JavaScript on siteA.com accessing private information you've chosen to share only with siteB.com. Without the same-origin policy, JavaScript written by the authors of siteA.com could have your browser make requests to siteB.com, using your authentication cookies for siteB.com. In this way, siteA.com could steal the secret information you share with siteB.com.
Sometimes you need to work cross domain, which is where CORS comes in. CORS relaxes the same-origin policy for siteB.com, using the Access-Control-Allow-Origin header to list other domains (siteA.com) that are trusted to run JavaScript that can interact with siteB.com.
To understand which domain should serve the CORS headers, consider this. You visit malicious.com, which contains some JavaScript that tries to make a cross domain request to mybank.com. It should be up to mybank.com, not malicious.com, to decide whether or not it sets CORS headers that relax the same-origin policy, allowing the JavaScript from malicious.com to interact with it. If malicous.com could set its own CORS headers allowing its own JavaScript access to mybank.com, this would completely nullify the same-origin policy.
I think the reason for my bad intuition is the point of view I have when developing a site. It's my site, with all my JavaScript. Therefore, it isn't doing anything malicious, and it should be up to me to specify which other sites my JavaScript can interact with. When in fact I should be thinking: Which other sites' JavaScript are trying to interact with my site and should I use CORS to allow them?
From my own experience, it's hard to find a simple explanation why CORS is even a concern.
Once you understand why it's there, the headers and discussion becomes a lot clearer. I'll give it a shot in a few lines.
It's all about cookies. Cookies are stored on a client by their domain.
An example story: On your computer, there's a cookie for yourbank.com. Maybe your session is in there.
Key point: When a client makes a request to the server, it will send the cookies stored under the domain for that request.
You're logged in on your browser to yourbank.com. You request to see all your accounts, and cookies are sent for yourbank.com. yourbank.com receives the pile of cookies and sends back its response (your accounts).
If another client makes a cross origin request to a server, those cookies are sent along, just as before. Ruh roh.
You browse to malicious.com. Malicious makes a bunch of requests to different banks, including yourbank.com.
Since the cookies are validated as expected, the server will authorize the response.
Those cookies get gathered up and sent along - and now, malicious.com has a response from yourbank.
Yikes.
So now, a few questions and answers become apparent:
"Why don't we just block the browser from doing that?" Yep. That's CORS.
"How do we get around it?" Have the server tell the request that CORS is OK.
1. A client downloads javascript code MyCode.js from http://siteA - the origin.
The code that does the downloading - your html script tag or xhr from javascript or whatever - came from, let's say, http://siteZ. And, when the browser requests MyCode.js, it sends an Origin: header saying "Origin: http://siteZ", because it can see that you're requesting to siteA and siteZ != siteA. (You cannot stop or interfere with this.)
2. The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB, which I thought meant that MyCode.js was allowed to make cross-origin references to the site B.
no. It means, Only siteB is allowed to do this request. So your request for MyCode.js from siteZ gets an error instead, and the browser typically gives you nothing. But if you make your server return A-C-A-O: siteZ instead, you'll get MyCode.js . Or if it sends '*', that'll work, that'll let everybody in. Or if the server always sends the string from the Origin: header... but... for security, if you're afraid of hackers, your server should only allow origins on a shortlist, that are allowed to make those requests.
Then, MyCode.js comes from siteA. When it makes requests to siteB, they are all cross-origin, the browser sends Origin: siteA, and siteB has to take the siteA, recognize it's on the short list of allowed requesters, and send back A-C-A-O: siteA. Only then will the browser let your script get the result of those requests.
Using React and Axios, join a proxy link to the URL and add a header as shown below:
https://cors-anywhere.herokuapp.com/ + Your API URL
Just adding the proxy link will work, but it can also throw an error for No Access again. Hence it is better to add a header as shown below.
axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
.then(response => console.log(response:data);
}
Warning: Not to be used in production
This is just a quick fix. If you're struggling with why you're not able to get a response, you can use this.
But again it's not the best answer for production.
If you are using PHP, try adding the following code at the beginning of the php file:
If you are using localhost, try this:
header("Access-Control-Allow-Origin: *");
If you are using external domains such as server, try this:
header("Access-Control-Allow-Origin: http://www.website.com");
I worked with Express.js 4, Node.js 7.4 and Angular, and I had the same problem. This helped me:
a) server side: in file app.js I add headers to all responses, like:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
This must be before all routes.
I saw a lot of added this headers:
res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
But I don’t need that,
b) client side: in sending by Ajax, you need to add "withCredentials: true," like:
$http({
method: 'POST',
url: 'url',
withCredentials: true,
data : {}
}).then(function(response){
// Code
}, function (response) {
// Code
});
If you want just to test a cross-domain application in which the browser blocks your request, then you can just open your browser in unsafe mode and test your application without changing your code and without making your code unsafe.
From macOS, you can do this from the terminal line:
open -a Google\ Chrome --args --disable-web-security --user-data-dir
In Python, I have been using the Flask-CORS library with great success. It makes dealing with CORS super easy and painless. I added some code from the library's documentation below.
Installing:
pip install -U flask-cors
Simple example that allows CORS for all domains on all routes:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
For more specific examples, see the documentation. I have used the simple example above to get around the CORS issue in an Ionic application I am building that has to access a separate flask server.
Simply paste the following code in your web.config file.
Noted that, you have to paste the following code under <system.webServer> tag
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
I can't configure it on the back-end server, but with these extensions in the browsers, it works for me:
For Firefox:
CORS Everywhere
For Google Chrome:
Allow CORS: Access-Control-Allow-Origin
Note: CORS works for me with this configuration:
For cross origin sharing, set header: 'Access-Control-Allow-Origin':'*';
Php: header('Access-Control-Allow-Origin':'*');
Node: app.use('Access-Control-Allow-Origin':'*');
This will allow to share content for different domain.
Nginx and Apache
As an addition to apsiller's answer, I would like to add a wiki graph which shows when a request is simple or not (and OPTIONS pre-flight request is send or not)
For a simple request (e.g., hotlinking images), you don't need to change your server configuration files, but you can add headers in the application (hosted on the server, e.g., in PHP) like Melvin Guerrero mentions in his answer - but remember: if you add full CORS headers in your server (configuration) and at same time you allow simple CORS in the application (e.g., PHP), this will not work at all.
And here are configurations for two popular servers:
turn on CORS on Nginx (nginx.conf file)
location ~ ^/index\.php(/|$) {
...
add_header 'Access-Control-Allow-Origin' "$http_origin" always; # if you change "$http_origin" to "*" you shoud get same result - allow all domain to CORS (but better change it to your particular domain)
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # arbitrary methods
add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; # arbitrary headers
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
}
turn on CORS on Apache (.htaccess file)
# ------------------------------------------------------------------------------
# | Cross-domain Ajax requests |
# ------------------------------------------------------------------------------
# Enable cross-origin Ajax requests.
# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
# http://enable-cors.org/
# change * (allow any domain) below to your domain
Header set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
Header always set Access-Control-Allow-Credentials "true"
The Access-Control-Allow-Origin response header indicates whether the
response can be shared with requesting code from the given origin.
Header type Response header
-------------------------------------------
Forbidden header name no
A response that tells the browser to allow code from any origin to
access a resource will include the following:
Access-Control-Allow-Origin: *
For more information, visit Access-Control-Allow-Origin...
For .NET Core 3.1 API With Angular
Startup.cs : Add CORS
//SERVICES
public void ConfigureServices(IServiceCollection services){
//CORS (Cross Origin Resource Sharing)
//=====================================
services.AddCors();
}
//MIDDLEWARES
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
//ORDER: CORS -> Authentication -> Authorization)
//CORS (Cross Origin Resource Sharing)
//=====================================
app.UseCors(x=>x.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:4200"));
app.UseHttpsRedirection();
}
}
Controller : Enable CORS For Authorized Controller
//Authorize all methods inside this controller
[Authorize]
[EnableCors()]
public class UsersController : ControllerBase
{
//ActionMethods
}
Note: Only a temporary solution for testing
For those who can't control the backend for Options 405 Method Not Allowed, here is a workaround for theChrome browser.
Execute in the command line:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="path_to_profile"
Example:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\Users\vital\AppData\Local\Google\Chrome\User Data\Profile 2"
Most CORS issues are because you are trying to request via client side ajax from a react, angular, jquery apps that are frontend basic libs.
You must request from a backend application.
You are trying to request from a frontend API, but the API you are trying to consume is expecting this request to be made from a backend application and it will never accept client side requests.

CORs problem before any code is hit, but only in browser XHR requests

I have an API built on CakePHP. It works for the most part but every once in a while browser access to the API dies. The error message on the XHR request response is:
'Access to XMLHttpRequest at 'http://be:8888/api/pings' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
However if I make exactly the same request via POSTMAN (or if I browse directly to the URL, rather than via XHR) it works without any trouble. I thought it might be a pre-flight OPTIONS issue but the request headers don't list a Request Method and the Apache access log shows these to be GET requests. There's nothing related in the Apache error log.
Restarting MAMP – i.e. Apache – does not fix the issue, nor does flushing the local DNS cache. The only thing that fixes it is a restart, after which it all works fine again for a few hours before eventually going on the blink again.
I can't think of what's causing this. I don't think it's a true CORS middleware error because the restart fixes it and the API is accessible normally. Also if I put a die in during the CORS middleware __invoke method it doesn't get that far (the die in the webroot index should be hit first anyway).
I get this error even if I disable the app by putting die('here'); at the start of the webroot index.php file.
Even if I delete the index.php files (both in the project root and webroot) so that browsing to the URL shows Apache's default error 404 not found: The requested URL /webroot/index.php was not found on this server, I still get the CORS errors when trying via XHR in the browser.
I've only noticed this issue since upgrading to Mac OS X Catalina.
What could be causing this?
[Update:]
Here's proof that it is working in the browser after a system restart:
Summary
URL: http://be:8888/api/clients
Status: 200 OK
Source: Network
Address: ::1.8888
Request
GET /api/clients HTTP/1.1
Accept: application/vnd.api+json
Content-Type: application/vnd.api+json
Origin: http://localhost:8080
Accept-Language: en-gb
Access-Control-Allow-Origin: *
Host: be:8888
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.5 Safari/605.1.15
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate
Connection: keep-alive
However, after a few hours it stops working. If it was actually a CORS issue my understanding is that it would NEVER work.
I'm not an Apache/PHP professional, but make sure you query HTTPS via HTTPS and http via http, other words, both sides should be same. Also, check the request header. And add "access-control-origin" in request header.

Server hosted on virtual machine with apache, cant seem to virtual machine local server

My Google compute engine virtual machine is hosting apache which is serving my website. When my website sends a post request to http://localhost:8080 It returns a 404, even though the (golang) server running in the file over can see url get requests.
I've tried adding Apache proxy all / calls to that server, But this seems to only work on Get requests put into the url.
To show that my server can see GET requests
[negroni] 2019/10/23 08:29:27.048676 Started GET /api/v1/login
[negroni] 2019/10/23 08:29:27.048941 Completed 404 Not Found in 262.947µs
While i need to be able to have it see the POST request
(axios.post('/api/v1/login', {username, password}))
Full request looks like
http://localhost:8992/api/v1/login
Here is the 'General' section of chrome Devtools Network
Request URL: http://localhost:8992/api/v1/login
Referrer Policy: no-referrer-when-downgrade
Here are the Request Headers
Provisional headers are shown
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
DNT: 1
Origin: https://carterstestdomain.store
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Any help is greatly appreciated.
Fixed this by following
Apache and Node.js on the Same Server
Also, As with me, The problem could be comming from the request being http instead of https :)

Exact Same Request Returns 200 to Postman but 404 to React App

Using Laravel's resource routes, I've set up an API to serve as the back-end of a React JS application. I'm attempting to access the 'update' method currently. I'm using Javascript's fetch() to accomplish this, so its making one OPTIONS request first, then making the POST request (the form has a method spoof in it, setting _method to PATCH instead - this obviously doesn't affect the initial OPTIONS call). This same page is also making a GET request to the same endpoint via the same method, which works fine.
The fetch() call is below. Of course, this being React, it's called through a Redux Saga process, but the actual fetch is there.
function postApi(values, endpoint, token) { // <-- values and endpoint are sent by the component, token is sent by a previous Saga function
return fetch(apiUrl + endpoint, { // <-- apiUrl is defined as a constant earlier in the file
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify(
values
)
}).then(handleApiErrors)
.then(response => response.json())
.catch((error) => {throw error})
}
And the Laravel routes:
Route::group(['middleware' => 'auth:api'], function() {
Route::resource('users', 'UserController');
}
I was encountering an error where the initial OPTIONS request to the URL was returning a 404 error, which right away is strange, since the endpoint obviously exists, the exact same endpoint having just been queried seconds ago, but I assumed maybe Laravel was returning the wrong error, and I had used the wrong method. I did some digging and debugging trying to get the request to be correct before giving up and making the request in Postman. The thing is: it works fine in Postman.
Here are the response headers from the server (note that any access origin is permitted):
Access-Control-Allow-Origin:*
Cache-Control:no-cache, private
Connection:close
Content-Length:10
Content-Type:text/html; charset=UTF-8
Date:Thu, 21 Sep 2017 13:29:08 GMT
Server:Apache/2.4.27 (Unix) OpenSSL/1.0.2l PHP/7.0.22 mod_perl/2.0.8-dev Perl/v5.16.3
X-Powered-By:PHP/7.0.22
Here's the request headers for the request as made from the React JS app (the one that receives a 404 error):
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8,fr;q=0.6,ga;q=0.4
Access-Control-Request-Headers:authorization,content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:localhost
Origin:http://localhost:3000
Pragma:no-cache
Referer:http://localhost:3000/employees/edit/13
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
In Postman, I set up those exact same request headers and made the exact same OPTIONS request to the server. And it worked fine! I received an empty 200 response.
Just to be sure, I double-checked the Apache access log. And sure enough:
...
::1 - - [20/Sep/2017:15:33:24 -0400] "OPTIONS /the/path/to/api/users/13 HTTP/1.1" 200 -
::1 - - [20/Sep/2017:15:40:26 -0400] "OPTIONS /the/path/to/api/users/13 HTTP/1.1" 404 10
...
Request method the exact same, request URL the exact same, except one returned 200, the other returned 404, for no discernable reason.
Additionally, I should add that another POST request, to the create method, works just fine.
What could be causing this?
ATTEMPTED SOLUTIONS
1. I saw this question (React Native + fetch + API : DELETE request fails in App, works in Postman), and even though I'm running Apache, not Nginx, I thought I'd try adding a trailing slash to the request URL. The OPTIONS request now returns a 301 error (moved permanently).
2. I removed the trailing slash and continued trying to fix. Per comment suggestion, I removed the automatic route generation and created my own:
Route::get('/users', 'UserController#index');
Route::post('/users', 'UserController#create');
Route::put('/users/{user}', 'UserController#update');
Route::patch('/users/{user}', 'UserController#update');
Route::get('/users/{user}', 'UserController#show');
The Postman request still returns 200 OK, and the React request still returns 404 Not Found.
3. Eureka! Kind of. Per another comment suggestion, I exported the request from Chrome as cURL and imported it into Postman directly - maybe I missed something when copying the headers over. It seems I did, because now the Postman request also returns 404!
After playing around with disabling and/or enabling the imported headers, I've determined that the issue is the combination of the Origin and Access-Control-Request-Method headers. If only one is present the request returns 200, but if both are present I receive a 404.
This does still leave me with the question of how to fix the problem, however. At this point I wonder if the question might become more of a Laravel question - IE, why an OPTIONS request to a perfectly valid Resource route would return 404. I assume because those resources routes are listening for PUT or PATCH but not OPTIONS.
Since you have your CORS set up, all you need to do next is handle the 'preflight' OPTIONS request. You can do this using a middleware:
PreflightRequestMiddleware:
if ($request->getMethod() === $request::METHOD_OPTIONS) {
return response()->json([],204);
}
return $next($request);
Add the above code in the handle() method of the newly created middleware. Add the middleware in the global middleware stack.
Also, do not forget to add the OPTIONS method to Access-Control-Allow-Methods in your CORS setup.
For more options, check this out.
Answer:
Read this article. When the browser sends OPTIONS request to your application, the application has no way of handling it since you only defined a GET/POST/DELETE/PUT/PATCH route for the given endpoint.
So, in order for this route to work with preflight requests:
Route::get('/users', 'UserController#index');
it would need a corresponding OPTIONS route:
Route::options('/users', 'UserController#options');
Note: You would use a middleware to handle all OPTIONS requests in one place. If, however, you are using OPTIONS requests for other purposes - check the first link in this answer for more options.

Configure Angularjs and CORS correctly using Apache running Flask api and Angularjs frontend on separate domain

This has been discussed all through Stackoverflow but I have not been able to find the solution for getting this to work. I even tried following alot of what was discussed in this post (Issues with CORS. Flask <-> AngularJS) since it was closly related to my setup, but I am still pretty much lost.
I have a python flask api server running locally. I have named this domain bac-api. Here is what this vhost looks like.
<VirtualHost *:80>
ServerName bac-api
WSGIDaemonProcess bacapi python-path=/home/lumberjacked/workspace/bas/development/lib/python2.7/site-packages
WSGIScriptAlias / /home/lumberjacked/workspace/bas/development/bac-api/bacapi.wsgi
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, application/json"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"
<Directory /home/lumberjacked/workspace/bas/development/bac-api>
WSGIProcessGroup bacapi
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
#SSLEngine on
#SSLCertificateFile /etc/apache2/ssl/bac_api_ssl.crt
#SSLCertificateKeyFile /etc/apache2/ssl/bac_api_ssl.key
</VirtualHost>
I have an angularjs site running as my front-end on a separate domain called manage.bac. I am writing an authentication service that connects to the bac-api and posts an api key and/or user credentials asking the server if the user is authenticated or not.
I can curl over to the server and this works and returns a response.
curl -X POST -H "Content-Type: application/json" -d '{ "api": "7f3d6d7338b921ae4ca95cecc452ef1790005ec10c2343fabe5a59ea" }' http://bac-api/authenticated/
response -- {"authenticated": false}
Also going to manage.bac and placing my login creditials email#email.com and password I get the same response but also I have configured it to return a 401 if you are not authenticated with a stored session.
POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1
The problems start when I switch over to ssl certs and port 443. So If on both domains I switch the vhost to port 443 and uncomment the ssl certs. After restarting apache there are no errors and the domains work as far as not showing any kind of 500 error or anything like that. I can curl over to the bac-api server using https and get a response.
curl -k -X POST -H "Content-Type: application/json" -d '{ "api": "7f3d6d7338b921ae4ca95cecc452ef1790005ec10c2343fabe5a59ea" }' https://bac-api/authenticated/
response -- {"authenticated": false}
But as soon as I go to https://manage.bac and redirect to the login page, all the trouble seems to start.
As soon as I click inside the login fields that console throws this error and I do not know if it is related or not.
Blocked a frame with origin "https://manage.bac" from accessing a frame with origin "chrome-extension://hdokiejnpimakedhajhdlcegeplioahd". The frame requesting access has a protocol of "https", the frame being accessed has a protocol of "chrome-extension". Protocols must match.
Here is my angularjs authentication code with the console.log methods outputting some stuff.
$http.post('https://bac-api/login/', user)
.success( function( user ) {
console.log('success');
console.log(user);
})
.error( function( error ) {
console.log('error');
console.log(error);
});
Object {email: "email#email.com", password: "password"} authentication-service.js:36
error authentication-service.js:50
authentication-service.js:51
When this error comes back there isn't anything in the response at all. I can see inside the network tab of chrome tools that this request is getting pre-flighted because it is sending an OPTIONS over to the server.
OPTIONS /login/ HTTP/1.1
Host: bac-api
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0
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
Origin: https://manage.bac
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Also I can see in the Network tab it is showing up as an OPTIONS and it has been cancelled. Which I do not know what that means.
I have configured inside angularjs with these options but it doesn't seem to make a difference on anything.
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
Also inside my flask application tried implementing the decorator mentioned here http://flask.pocoo.org/snippets/56/ and also mentioned in other stackoverflow posts. This doesn't seem to do anything either. Also I assumed that because I put inside my vhost the access headers for the api server that I really didn't need to do the same thing in the app. Though I could be totally wrong because I dont have a clue on what I'm doing.
Any help is really appreciated. I am sorry if this seems like a duplicate issue but so far I cannot get this to work and I have tried every post on stackoverflow that I can to solve this issue.
--- Edit with updated information
This morning as an experiment I switched both vhosts back over to port 80 and commented out all Allow access headers. Restarted and tried logging in again, here are my results.
Failed to load resource: Origin http://manage.bac is not allowed by Access-Control-Allow-Origin. http://bac-api/authenticated/
XMLHttpRequest cannot load http://bac-api/authenticated/. Origin http://manage.bac is not allowed by Access-Control-Allow-Origin. manage.bac/:1
So after this error I went inside my bac-api vhost and un-commented Header set Access-Control-Allow-Origin "*" and re-started again and tried logging in. Here are the new errors that display.
OPTIONS http://bac-api/authenticated/ Request header field Content-Type is not allowed by Access-Control-Allow-Headers. angular.js:9312
(anonymous function) angular.js:9312
sendReq angular.js:9146
$http angular.js:8937
Authenticator.isLoggedIn authentication-service.js:13
RouteConfig.login.resolve.Auth state-service-provider.js:16
invoke angular.js:2902
(anonymous function) angular-ui-router.js:801
forEach angular.js:137
resolve angular-ui-router.js:797
resolveState angular-ui-router.js:813
transitionTo angular-ui-router.js:704
(anonymous function) angular-ui-router.js:615
invoke angular.js:2902
handleIfMatch angular-ui-router.js:433
rule angular-ui-router.js:452
update angular-ui-router.js:487
Scope.$broadcast angular.js:8307
afterLocationChange angular.js:5649
(anonymous function) angular.js:5637
Scope.$eval angular.js:8057
Scope.$digest angular.js:7922
Scope.$apply angular.js:8143
(anonymous function) angular.js:981
invoke angular.js:2895
resumeBootstrapInternal angular.js:979
bootstrap angular.js:993
angularInit angular.js:954
(anonymous function) angular.js:14843
c jquery-1.10.1.min.js:4
p.fireWith jquery-1.10.1.min.js:4
x.extend.ready jquery-1.10.1.min.js:4
q jquery-1.10.1.min.js:4
XMLHttpRequest cannot load http://bac-api/authenticated/. Request header field Content- Type is not allowed by Access-Control-Allow-Headers. manage.bac/:1
So to resolve this error and allow the Content-Type through I go back to my bac-api vhost and I add back Header set Access-Control-Allow-Headers "Content-Type". After restarting browsing to manage.bac on page load here are those results.
POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1
Which this is good because it means I received an {"authenticated": false} response and it sent back a 401 unauthorized. If I continue and try to log in I get these results.
Object {email: "email#email.com", password: "password"} authentication-service.js:36
success authentication-service.js:40
Object {login: false} authentication-service.js:41
This also is working. Here is the angularjs code that is producing this output.
$http.post('http://bac-api/login/', user)
.success( function( user ) {
console.log('success');
console.log(user);
})
.error( function( error ) {
console.log('error');
console.log(error);
});
Now my thoughts were awesome if its working on port 80 I can switch it over to port 443 now and keep rolling. So I switch the vhosts to port 443 and browse to manage.bac again to log in. On page load before even trying to log in I get these results.
And again when I try to log in and submit the form I get these results also.
Object {email: "email#email.com", password: "password"} authentication-service.js:36
error authentication-service.js:50
authentication-service.js:51
And also on the Network tab
This was just to try and give every body more information in helping me find the reason for this problem.
----- Edit again with more information
Tonight I started trying to test this with curl and see what headers were coming back with an OPTIONS request
Here is the curl request I copied it directly out of the Network tab assuming this was the same OPTIONS request that angularjs is sending over. First Ill put the OPTIONS request from the network tab and then my curl request.
OPTIONS https://bac-api/login/ HTTP/1.1
Access-Control-Request-Method: POST
Origin: https://manage.bac
Referer: https://manage.bac/
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36
Access-Control-Request-Headers: accept, origin, x-requested-with, content-type
curl -i -k -X OPTIONS -H "Access-Control-Request-Method: POST" -H "Origin: https://manage.bac" -H "Referer: https://manage.bac/" -H "Access-Control-Request-Headers: accept, origin, content-type" https://bac-api/login/
Here is the response from curl
HTTP/1.1 200 OK
Date: Tue, 01 Oct 2013 02:51:17 GMT
Server: Apache/2.2.22 (Ubuntu)
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Max-Age: 21600
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST, GET, OPTIONS
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
This seems to indicate that the server is configured correctly and responding to OPTIONS requests with the correct headers. But as I have posted in the pictures above when I run this in the browser still on the Network tab it is getting cancelled and nothing comes back in the error response.
I was able to solve this problem and it was the stupidest thing. I will dig up the other stackoverflow posts that helped lead me to the solution. But basically during testing I generated self signed certificates to use locally. Apparently both firefox and chrome will automatically cancel your requests if it does not trust the certificates when doing cross domain posts. I had to go into both chrome and firefox to add the certificates and mark them as trusted before they stopped cancelling the request. Now everything works perfectly.
Also in this investigation I found out that you do not need to add into Flask the requests helper to add headers to your responses and in your Apache configuration. If you put them in both it will add headers both times. In my configuration I chose to add it to my Apache configuration because it made my python code alot cleaner.