Error connecting to azure blob storage API from R

后端 未结 3 1893
长情又很酷
长情又很酷 2020-12-17 02:44

I am attempting to work with Azure storage via the REST API in R. I\'m using the package httr which overlays Curl.

Setup

You can use R-fiddle: http://www.r

3条回答
  •  暖寄归人
    2020-12-17 02:58

    Worked trough the example code by MrFlick above and to get it to work I had to change a few things.

    The date string has to be set in an English locale, for example:

    lct <- Sys.getlocale("LC_TIME") 
    Sys.setlocale("LC_TIME", "us")
    requestdate <- format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
    Sys.setlocale("LC_TIME", lct)
    

    The 'signaturestring' should be formated with \n between parameters:

     signaturestring <- paste0("GET", paste(rep("\n", 12), collapse=""),
    "x-ms-date:", requestdate, 
    "\nx-ms-version:2009-09-19\n/preconstuff/pings\ncomp:list\nrestype:container")
    

    EDIT: Following procedure works for me. Based on Steph Locke example.

    library(httr)
    library(RCurl)
    
    azureBlobCall <- function(url, verb, key, requestBody=NULL, headers=NULL, ifMatch="", md5="") { 
      urlcomponents <- httr::parse_url(url)
      account <- gsub(".blob.core.windows.net", "", urlcomponents$hostname, fixed = TRUE)
      container <- urlcomponents$path
    
      # get timestamp in us locale
      lct <- Sys.getlocale("LC_TIME"); Sys.setlocale("LC_TIME", "us")
      `x-ms-date` <- format(Sys.time(),"%a, %d %b %Y %H:%M:%S %Z", tz="GMT")
      Sys.setlocale("LC_TIME", lct)
    
      # if requestBody exist get content length in bytes and content type
      `Content-Length` <- ""; `Content-Type` <- ""
      if(!is.null(requestBody)) {
        if(class(requestBody) == "form_file") {
          `Content-Length` <- (file.info(requestBody$path))$size
          `Content-Type` <- requestBody$type 
        } else {
          requestBody <- enc2utf8(as.character(requestBody))
          `Content-Length` <- nchar(requestBody, "bytes")
          `Content-Type` <- "text/plain; charset=UTF-8" 
        }
      } 
    
      # combine timestamp and version headers with any input headers, order and create the CanonicalizedHeaders
      headers <- setNames(c(`x-ms-date`, "2015-04-05",  unlist(headers)), 
                          c("x-ms-date", "x-ms-version", unclass(names(unlist(headers)))))
      headers <- headers[order(names(headers))]
      CanonicalizedHeaders <- paste(names(headers), headers, sep=":", collapse = "\n")
    
      # create CanonicalizedResource headers and add any queries to it
      if(!is.null(urlcomponents$query)) {
        components <- setNames(unlist(urlcomponents$query), unclass(names(unlist(urlcomponents$query))))
        componentstring <- paste0("\n", paste(names(components[order(names(components))]),
                                              components[order(names(components))], sep=":", collapse = "\n"))
      } else componentstring <- ""
      CanonicalizedResource <- paste0("/",account,"/",container, componentstring)
    
      # create the authorizationtoken
      signaturestring <- paste0(verb, "\n\n\n", `Content-Length`, "\n", md5, "\n", `Content-Type`, "\n\n\n", 
                                ifMatch, "\n\n\n\n", CanonicalizedHeaders, "\n", CanonicalizedResource)
    
      requestspecificencodedkey <- RCurl::base64(
        digest::hmac(key=RCurl::base64Decode(key, mode="raw"),
                     object=enc2utf8(signaturestring),
                     algo= "sha256", raw=TRUE)
      )
    
      authorizationtoken <- paste0("SharedKey ", account, ":", requestspecificencodedkey)
    
      # make the call
      headers_final <- add_headers(Authorization=authorizationtoken, headers, `Content-Type` = `Content-Type`)
      call <- httr::VERB(verb=verb, url=url, config=headers_final, body=requestBody, verbose())
    
      print("signaturestring");print(signaturestring); 
      print(headers_final); print(call)
      return(content(call))
    } 
    
    ## Tests. Replace 'key' and 'accountName' with yours
    key <- "YowThr***********RDw=="
    
    # Creates a container named 'test'
    azureBlobCall("https://accountName.blob.core.windows.net/test?restype=container", "PUT", key)
    # Creates a blob named 'blob' under container 'test' with the content of "Hej världen!"
    azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "PUT", key, 
                  headers = c("x-ms-blob-type"="BlockBlob"), requestBody = "Hej världen!") #upload_file("blob.txt"))
    # List all blob in the container 'test'
    azureBlobCall("https://accountName.blob.core.windows.net/test?comp=list&restype=container", "GET", key)
    # deletes the blobl named 'blob' 
    azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "DELETE", key)
    # Creates a blob named 'blob' under container 'test' with and upload the file 'blob.txt'
    azureBlobCall("https://accountName.blob.core.windows.net/test/blob", "PUT", key, 
                  headers = c("x-ms-blob-type"="BlockBlob"), requestBody = upload_file("blob.txt"))
    # deletes the container named 'test' 
    azureBlobCall("https://accountName.blob.core.windows.net/test?restype=container", "DELETE", key)
    

提交回复
热议问题