Using cors across two independently running local apps - scala

I have two applications running indepepently, one taking care of my backend (written in Scala Play) then other one being my frontend (Angular with a static Node server).
I try to request data on my frontend through a form from my Scala Play app.
this.insertionOrder = function(){
$http({
method: 'POST',
url: '//localhost:9000/insertsupplier',
header: {
'Content-type': 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS'
},
data:{
'supplier_id': 1,
'suppliername': 'xxx',
'supplier_address': 'xxx xxx xxx xxx',
'contact': 'xxx#xxx.com',
'datecreated': '2017-10-15T09:45:00.000UTC+00:00'
}
}).then(function(response){
console.log(response);
return response.data
}, function(err){
console.log(err)
});
};
and my play app looks like this:
Controller:
def insertsupplier = Action(parse.json) { implicit request =>
val json = request.body
val sup: Supplier = json.as[Supplier]
sup.insertSql(con)
Ok("test")
}
my build.sbt contains filters:
libraryDependencies ++= Seq(
cache ,
ws,
jdbc,
filters
)
and the MyFilters.scala
class MyFilters (implicit inj:Injector) extends HttpFilters with Injectable {
implicit val as = inject[ActorSystem]
implicit val mat = ActorMaterializer()
val gzip = new GzipFilter()
val csrf = inject[CSRFFilter]
val cors = inject[CORSFilter]
//println(s"csrf: ${csrf.tokenProvider}")
//println(s"csrf: ${csrf.tokenProvider.generateToken}")
def filters = Seq(gzip,cors,csrf)
}
and finally my application.conf
play.filters.cors {
pathPrefixes = ["*"]
allowedOrigins = ["http://localhost:3000","https://localhost:3000","http://localhost:3000/*","https://localhost:3000/*"]
allowedHttpMethods = ["GET", "POST", "OPTIONS"]
allowedHttpHeaders = ["Accept"]
# preflightMaxAge = 1 hour
}
play.filters.csrf {
cookie.name = "XSRF-TOKEN"
header.name = "X-XSRF-TOKEN"
}
play.http.filters = "filters.MyFilters"
I keep getting the error "XMLHttpRequest cannot load http://localhost:9000/insertsupplier. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500."
I feel that first my CORS setup is wrong anyway --> What needs to be changed? I am new to this.
And am I even able to use cors in order to access data from localhost?

It may be that there’s nothing wrong at all with your CORS setup, because the “The response had HTTP status code 500” part of the error message indicates that the actual immediate problem is that an OPTIONS request to your server caused some unexpected failure on the server side.
From just the code snippets in the question, it’s not possible to tell what might be causing that 500 failure in the server side. It may be completely unrelated to your CORS config.
But regardless, you should drop the parts of your frontend code that are adding the header 'Access-Control-Allow-Origin' : '*', and 'Access-Control-Allow-Methods'. Those headers are response headers that must be sent from the server side, not from frontend code.
But the 'Content-type': 'application/json' part of your frontend code is valid, and assuming it’s actually necessary in order to get the expected response from the server, there’s no way you can make your request without triggering browsers to do a CORS preflight OPTIONS request.
But if the CORS preflight OPTIONS request fails, the browser never gets around to trying the POST request your code is actually attempting to send. And if your backend responds to that OPTIONS request with a 500 response, then the preflight fails. It must instead respond with a 200 or 204.

Related

Abort spray request when aborted from reactjs

I am new to scala and spray. I am able to abort request from reactJS. And it shows in network tab of browser console that the request is cancelled. But from scala it is not aborting. In logs i can see
api is getting hitted. For Rest API I am using spray in scala.
Here is my reactJS code:
new Promise((accept, _reject) => {
fetch("/api/complete", {
method: "post",
signal: controller.signal,
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(requestBody)
})
Ans here is my scala code:
pathPrefix("complete") {
post {
entity(as[completeRequest]) { completeRequest =>
complete {
completeService()
}
}
}
}
def completeService(): Future[HttpResponse] = {
val pipeline: HttpRequest => Future[HttpResponse] = sendReceive ~> unmarshal[HttpResponse]
val response: Future[HttpResponse] = pipeline(Post(someremoteUrl.concat("complete"), botCompleteRequest)
~> addHeader("demo", "test"))
response
}
So how to abort this complete request when it is aborted from reactJS/promise
Short answer: You don't.
It does matter if it is React (or Angular, or jQuery) on the client-side and it does not matter what is on the server-side (scala, PHP, .NET).
What matters is the HTTP between client and server.
In HTTP you can't "catch" a request that is already sent. The abort function in js/browser pretty much only means that it will ignore the response. Once a request is sent and is in the network, it will hit the server, and the server will process it. The server never gets notified that the client canceled the request.
This question and the answer cover the topic quite well: https://softwareengineering.stackexchange.com/questions/362187/can-a-caller-abort-an-execution-of-code-invoked-by-http-request

Axios sending OPTIONS instead GET

I'm trying to make api calls locally in a react app using axios.
I've already added django-cors-headers and followed the documentation, but it does not seem to be working.
I always get the error:
localhost/:1 Access to XMLHttpRequest at 'http://127.0.0.1:8000/api/todos/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
my base.py:
INSTALLED_APPS = [
# ...
"corsheaders",
"rest_framework",
"todo",
"api",
]
MIDDLEWARE = [
# ...
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
# ...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = False
In my react app:
const [todos, setTodos] = useState({})
useEffect(
() => {
axios.get(
api_url, {
headers: {
"Access-Control-Allow-Origin": "*",
}
}
).then(
res => {
setTodos(res.data);
console.log(res.data)
}
).catch(
err => {
console.log(err)
}
)
}, []
)
Note, even without configuring a whitelist and reverting the CORS settings to:
CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
I still manage to get the data in a get call using httpie, just running http + url.
Note 2: When the axios tries to get the data, I get this on the terminal running the Django app:
[04/Jun/2019 18:15:29] "OPTIONS /api/todos/ HTTP/1.1" 200 0
IMPORTANT EDIT:
The problem does not seem to be with my server, I used fetch instead of Axios and everything occurred normally. With Axios, my server was getting an OPTIONS method, and, I do not know why, I was giving this problem with CORS.

Jersey CORS configuration to allow response cookies from server

I have a Jersey REST interface that I want to send cookies in its responses to each request but no cookies are ever present in any response.
I have a feeling it's a CORS issue and I'm not sure what CORSResponseFilter configuration I need to allow cookies to be set and successfully sent in a response.
My project is built with SpringBoot under Kotlin.
Response code:
#POST
fun put(): Response {
val cookie = NewCookie(Cookie("RESERVATION", "TEST"),
"Session", 60 * 60, false)
return ok()
.cookie(cookie)
.entity(Result("OK", "Success"))
.build()
}
Filter code:
open class CORSResponseFilter : ContainerResponseFilter {
override fun filter(req: ContainerRequestContext?, res: ContainerResponseContext?) {
res?.headers?.add("Access-Control-Allow-Origin", "*")
res?.headers?.add("Access-Control-Allow-Methods", "POST, GET")
res?.headers?.add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
res?.headers?.add("Access-Control-Expose-Headers", "Set-Cookie")
res?.headers?.add("Access-Control-Allow-Credentials", "true")
}
}
Requests are successful and the responses send otherwise as intended but all without any cookies. Prior to setting up the response filter I was able to receive cookies in each response.
Any help is appreciated.

Angular2-Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource

I am calling a http post in Angular 2. This is working fine in post man but when I implement this API call in Angular 2 I get No 'Access-Control-Allow' error. Here is my code
getInspections(): Observable<IInspection[]> {
if (!this.inspections) {
let body =JSON.stringify({"Statuses":["Submitted", "Opened"]});
let headers = new Headers({ 'Content-Type': 'application/json' });
headers.append('Access-Control-Allow-Origin','*');
let options = new RequestOptions({ headers: headers });
return this.http.post(this._baseUrl + '/api/Inspect/ListI',body,options)
.map((res: Response) => {
this.inspections = res.json();
return this.inspections;
})
.catch(this.handleError);
}
else {
//return cached data
return this.createObservable(this.inspections);
}
}
Or can I do this? Just pass header instead of options
getInspections(): Observable<IInspection[]> {
if (!this.inspections) {
let body =JSON.stringify({"Statuses":["Submitted", "Opened"]});
let headers = new Headers({ 'Content-Type': 'application/json' });
//headers.append('Access-Control-Allow-Origin','*');
// let options = new RequestOptions({ headers:headers });
return this.http.post(this._baseUrl + '/api/Inspect/ListI',body,headers)
.map((res: Response) => {
this.inspections = res.json();
return this.inspections;
})
.catch(this.handleError);
}
else {
//return cached data
return this.createObservable(this.inspections);
}
}
CORS headers like
headers.append('Access-Control-Allow-Origin','*');
need to be provided by the server. Adding them on the client is pointless.
When using non-standard headers (json is apparently considered non-standard) then a pre-flight check is carried out to ask if the requested action (in this case 'post') can be carried out. Only the server can respond with the permissive headers. How you respond does depend on your server language. In my webapi2 I implement cors in the WebAppConfig
var cors = new EnableCorsAttribute("http://localhost:3000", "*", "GET, HEAD, OPTIONS, POST, PUT");
cors.SupportsCredentials = true;
config.EnableCors(cors);
Note for a live server you would replace the localhost ref with a web configed list ( or specific location where the caller resides). The SupportsCredentials is only needed if you are using authentication.
To handle the pre-flight I added a method to Globals.asax which just intercepts pre-flight messages and returns enough data for the post to move ahead.
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
var origin = HttpContext.Current.Request.Headers["Origin"];
Response.Headers.Add("Access-Control-Allow-Origin", origin);
Response.Headers.Add("Access-Control-Allow-Headers", "content-type, withcredentials, Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
Response.Headers.Add("Access-Control-Allow-Credentials", "true");
Response.Headers.Add("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS, POST, PUT");
Response.Flush();
}
}
Note here that I am cheating somewhat by reflecting the origin back - this is not safe in a production environment and should list the specific servers otherwise you are being too loose with security.
Be aware that there are some dev cheats. - If you run on internet explorer on localhost (for dev purposes) then ie ignores the port which most other browsers do not so making things easier. There is also a CORS enhancement for Chrome which adds the headers for you. Finally you will see a lot of code that uses '*' returns (to permit all) - by all means use them to get the code working but before release lock these down far more aggressively.

How to handle Header "Access-Control-Allow-Origin" using ampersand-rest-collection?

Trying to request cors request with code:
export default Collection.extend({
model: person,
url () {
return 'http://127.0.0.1:5000/person/'
},
ajaxConfig: function () {
return {
headers: {
'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000'
},
xhrFields: {
withCredentials: false
}
};
},
})
I'm sending request with http//:127.0.0.1:3000 but if use * i still get error below
XMLHttpRequest cannot load http://127.0.0.1:5000/person/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
How to handle this kind of request?
Rather than your Collection sending the 'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000' in its request headers, your server at http://127.0.0.1:5000 needs to send it in its response headers to the pre-flight request.
If you can give some details about the server setup, I can help you to figure out how to add the header to the response.