我正在构建一个R REST API,我可以在其中公开一些R函数/模型。
我从这个问题开始: Suggestions needed for building R server REST API's that I can call from external app?
添加了一些额外的处理,并开始使用httpuv
的守护程序服务器功能。
它已经起作用了。我担心的是这样做是否安全。我怎么能确定我对不正确的请求做出了正确的回应,并且一个人无法意外/恶意地注入代码。
现在,他们可以使用http://IPADDRESS:PORT/FUNCTION?a=VALUE&b=VALUE
调用api在所有文本解析过程中是否有一种好方法可以验证我的输入?
(这都在我们的内部网络上,所以我不太关心恶意方面,但我真的很想知道这里的限制)
这是“这里有龙”的情况吗?
CODE:
library(httpuv)
library(RCurl)
library(httr)
library(jsonlite)
从一些功能开始:
#################################################################################
# API Functions
#################################################################################
APIoperations <-
list(
Add = function(a,b) a + b,
Subtract = function(a,b) a - b,
Multiply = function(a,b) a*b,
Divide = function(a,b) a/b
)
做一些验证:
#################################################################################
# Check if Operation is Supported
#################################################################################
validateOperation <- function(op) {
if(op %in% names(APIoperations)) {
op
} else {
# DO OTHER THINGS HERE
# LOG, etc...
'Unsupported'
}
}
错误格式:
#################################################################################
# General Error Format
#################################################################################
returnError <- function(error = '',
status = 500L,
headers = list('Content-Type' = 'text/html'),
body = paste('\r\n<html><body>',error,'</body></html>')) {
list(status = status,
headers = headers,
body = body)
}
然后是我的实际服务器逻辑:
#################################################################################
#################################################################################
# Start Server Logic
#################################################################################
#################################################################################
app <-
list(call =
function(req) {
#################################################################################
# Grab and Parse Query
# Only include acceptable characters
query <- req$QUERY_STRING
if(validateOperation(gsub('[[:punct:]]','',req$PATH_INFO)) == 'Unsupported') {
return(list(status=501L,
headers=list('Content-Type' = 'text/html'),
body= "\r\n<html><body>Error 501<br>Unsupported Operation</body></html>"))
}
#################################################################################
# Strip any punctuation in this case, other cases may need a specific parsing
funcname <- gsub('[[:punct:]]','',req$PATH_INFO)
#################################################################################
# Requested Function
reqfunc <- APIoperations[[funcname]]
#################################################################################
# Function Parameters
vars <- names(formals(reqfunc))
#################################################################################
# Parse
qs <- try(httr:::parse_query(gsub("^\\?", "", query)))
#################################################################################
# If missing vars return error
if(!all(names(qs) %in% vars) | !all(vars %in% names(qs))) {
errorFeed <- 'Missing Variables, or improper Code'
returnError(errorFeed)
}
#################################################################################
# Return Status 200 and type JSON
status <- 200L
headers <- list('Content-Type' = "application/json")
if (!is.character(query) || identical(query, "")) {
body <- "\r\n<html><body></body></html>"
} else {
body <- jsonlite::toJSON(x = list(result = do.call(reqfunc,lapply(qs,as.numeric))))
}
# Print Query String for testing purposes
print(req$QUERY_STRING)
ret <- list(status=status,
headers=headers,
body=body)
return(ret)
}
message("Starting server...")
然后我用:
启动服务器server <- httpuv::startDaemonizedServer(<MYIPADDRESS>, <PORT>, app=app)
然后停止:
httpuv::stopDaemonizedServer(server)