-
Notifications
You must be signed in to change notification settings - Fork 256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable CORS in Plumber #66
Comments
I am also getting |
@trestletech may come up with a push-button solution at some point, but for now I'm pretty sure that you can totally do this:
|
I spent a little time looking into this today. The bad news is that it's going to get worse before it gets better. 😬 Two decisions:
|
For now does @scottmmjackson's approach still work in v0.4.0? |
@trestletech I wonder if there's been any activity or further thinking on this front? I'm hugely excited about plumber, but without CORS support it's much harder to harness its potential. |
How about extending the advanced Docker example, which already has an nginx webserver, with code how to add CORS headers to an endpoint that nginx is a proxy for? nginx as a web server is made for such tasks, and if you're really running an app in production you often run it behind a webserver (for https, for example) anyway. |
I think it's important to note that the workaround above did not work for me and at least one another. The modified example here, #143 (comment), with the |
#' @filter cors
cors <- function(req, res) {
res$setHeader("Access-Control-Allow-Origin", "*")
if (req$REQUEST_METHOD == "OPTIONS") {
res$setHeader("Access-Control-Allow-Methods","*")
res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
res$status <- 200
return(list())
} else {
plumber::forward()
}
} @nteetor Please try the above code. It is working for me |
Yes, I was able to get cors up and running, thank you though. |
By simply adding the code provided by @shizidushu at the top of my plumber file, it solved this issue for me. |
Hi. i am not able to resolve my cors issue. The cors function(req,res) solution provided by @shizidushu need any parameters ? I have the following code in my main R script. r22 <- plumb("/script1.R") r22$run(port=xxxx, host="x.x.x.x") should i pass r22 or any other code to the function ? Please respond its urgent. thanks a ton |
@bala7123 the code provided by @shizidushu in #66 (comment) should exist within your |
Thie solution given by #66 (comment) doesn't work for me: the filter is never called. I'm having programmatic routers (see code below). Whenver I request
My code:
|
The filter must be added programmatically, if the router is also defined programatically. (The Instead, add it directly: router$filter("cors", cors) |
Aah, thanks! I thought is was something like that, but couldn't find it in the docs. I may have missed it... Solved. |
Thank you for this (see above). It works! Many solutions only state a simpler version like below:
However, when calling the API with a JSON POST body and a header set explicitly to "content-type: application/json", this simpler version fails with a CORS error anyway. The more elaborate version by shizidushu, however, works! Can someone explain what happens in the 'if' part? The request I described runs through the function twice (automatically). The first time only the 'if' part is executed, the second time the 'else'. How is this happening? I do undertand the plumber::forward() command. But in the 'if' part an empty list is returned. How is it that the code-excution doesn't stop there? Plumber calls itself somehow? |
Your client is calling plumber the second time with the headers set in the if. If you do not do a plumber::forward(), plumber respond back to the client |
So.... because the header in the response to the client (browser side) is altered/set by the server (plumber side), the client, based on that 'new' header in the response resends its request using a different header? (which then ends up in the 'else' part). |
Use your browser debugger to inspect browser traffic with your plumber server. You can see the headers from there. https://developers.google.com/web/tools/chrome-devtools/network/ |
Thanks meztez for pointing me in the right direction. I did inspect the browser debugger en saw that it it indeed sends two API calls when using the javascript 'fetch' method and setting It is explained in more detail in this answer on stackoverflow: That also explains why the more elaborate cors filter (as posted by @shizidushu) works and the simpler version (without the if/else) doesn't. |
If you have two domains that you want to restrict CORS to, how do you do this? I've only seen examples with one address or *. |
You could build something from this knowledge https://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains.
#' @filter cors
cors <- function(req, res) {
if (req$HTTP_ORIGIN %in% c("domain1", "domain2") {
res$setHeader("Access-Control-Allow-Origin", req$HTTP_ORIGIN)
if (req$REQUEST_METHOD == "OPTIONS") {
res$setHeader("Access-Control-Allow-Methods",req$HTTP_ORIGIN)
res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
res$status <- 200
return(list())
} else {
plumber::forward()
}
}
} |
@meztez the value of
What am I missing? |
Nothing. The code I provided was a mock, I'm not sure of the exact header that would contain the origin in your case. yes req is an environment. # Enable CORS Filtering
#' @filter cors
cors <- function(req, res) {
# For debug/dev purpose remove when you find which header you need
for (h in grep("^HTTP", ls(envir = req), value = TRUE)) { print(h); print(req[[h]])}
if (req$HTTP_ORIGIN %in% c("http://localhost:3000",
"https://testingdomain.com",
"https://productiondomain.com")) {
res$setHeader("Access-Control-Allow-Origin", req$HTTP_ORIGIN)
if (req$REQUEST_METHOD == "OPTIONS") {
res$setHeader("Access-Control-Allow-Methods",req$HTTP_ORIGIN)
res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
res$status <- 200
return(list())
} else {
plumber::forward()
}
}
} |
There appears to be three variables it could be when
I went with the first, as follows: # Enable CORS Filtering
#' @filter cors
cors <- function(req, res) {
safe_domains <- c("http://localhost:3000",
"https://testingdomain.com",
"https://productiondomain.com")
if (any(grepl(pattern = paste0(safe_domains,collapse="|"), req$HTTP_REFERER,ignore.case=T))) {
res$setHeader("Access-Control-Allow-Origin", req$HTTP_REFERER)
if (req$REQUEST_METHOD == "OPTIONS") {
res$setHeader("Access-Control-Allow-Methods",req$HTTP_REFERER)
res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
res$status <- 200
return(list())
} else {
plumber::forward()
}
}
} Looking at Mozilla cors docs, it looks like the origin is the base domain while the referer is the full path. |
The above solution is unstable, and you can never see the swagger documentation. Right now I have this working solution (implemented without fully understanding # Enable CORS Filtering
#' @filter cors
cors <- function(req, res) {
safe_domains <- c("http://localhost:3000",
"https://testingdomain.com",
"https://productiondomain.com")
if (any(grepl(pattern = paste0(safe_domains,collapse="|"), req$HTTP_REFERER,ignore.case=T))) {
res$setHeader("Access-Control-Allow-Origin", sub("/$","",req$HTTP_REFERER)) #Have to remove last slash, for some reason
if (req$REQUEST_METHOD == "OPTIONS") {
res$setHeader("Access-Control-Allow-Methods","GET,HEAD,PUT,PATCH,POST,DELETE") #This is how node.js does it
res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
res$status <- 200
return(list())
} else {
plumber::forward()
}
} else {
plumber::forward()
}
} |
As @schloerke said in #604 "CORS implementation" (Jul 21, 2020), to enable CORS he recommended the code of the comment of @shizidushu on Sep 5, 2018 in this current issue. (Thanks @shizidushu). (It works for me). But before that I had missed the use of
from https://www.rplumber.io/articles/security.html#cross-origin-resource-sharing-cors |
So funny that I just did the same thing ^ spent 30 minutes trying all of this until I really read the last comment and realized you have to TAKE AWAY |
I am trying to make a POST request through my chrome browser, but its showing error of
preflight request
.Please suggest a way to
enable CORS at Plumber side
.The text was updated successfully, but these errors were encountered: