2017-02-21 4 views
0

У меня возникли проблемы с использованием httr, чтобы отправить файл Salesforce's REST API. Я подумал, что this SO question может позаботиться об этом, но не показалось. У меня есть подозрение, что это происходит потому, что Saleforce хочет недвоичная часть и upload_file создает объект класса form_file, который обрабатывается как двоичный файл, но, возможно, кто-то есть альтернативное объяснение/решение ...Как POST multipart двоичный и не двоичный с httr (для Salesforce API)

Salesforce просит следующее локон запрос вставить новый документ:

curl https://yourInstance.salesforce.com/services/data/v23.0/sobjects/Document/ -H 
"Authorization: Bearer token" -H "Content-Type: multipart/form-data; 
boundary=\"boundary_string\"" --data-binary @newdocument.json 

с newdocument.json глядя, как это:

--boundary_string 
Content-Disposition: form-data; name="entity_document"; 
Content-Type: application/json 
{ 
"Description" : "Marketing brochure for Q1 2011", 
"Keywords" : "marketing,sales,update", 
"FolderId" : "005D0000001GiU7", 
"Name" : "Marketing Brochure Q1", 
"Type" : "pdf" 
} 
--boundary_string 
Content-Type: application/pdf 
Content-Disposition: form-data; name="Body"; filename="2011Q1MktgBrochure.pdf" 
Binary data goes here. 
--boundary_string-- 

Если я пытаюсь произвести так imilar выход, используя @ ответ Jeroen в качестве полезного руководства, я получаю Плохую ошибку запроса:

library(httr) 
library(jsonlite) 

url <- "https://[Salesforce Instance]/services/data/v39.0/sobjects/Document/" 
header <- add_headers(c(Authorization = "Bearer [Salesforce Key]")) 

media <- tempfile() 
png(media, width = 800, height = 600) 
plot(cars) 
dev.off() 

metadata <- tempfile() 
x <- data.frame(FolderId="a0a1300000ZG7u3", Name="test.png") #Salesforce Record ID and file name 
json <- toJSON(unbox(x), pretty=T) 
writeLines(json, metadata) 

body <- list(entity_document = upload_file(metadata, type = "application/json; charset=UTF-8"), 
      Body = upload_file(media, type = "image/png")) 


req <- POST(url, header, verbose(), body = body) 

(подробный вывод)

-> POST /services/data/v39.0/sobjects/Document/ HTTP/1.1 
-> Host: [Salesforce Instance] 
-> User-Agent: libcurl/7.51.0 r-curl/2.3 httr/1.2.1.9000 
-> Accept-Encoding: gzip, deflate 
-> Accept: application/json, text/xml, application/xml, */* 
-> Authorization: Bearer [Salesforce Key] 
-> Content-Length: 3720 
-> Expect: 100-continue 
-> Content-Type: multipart/form-data; boundary=------------------------6525413b2350e313 
-> 
<- HTTP/1.1 100 Continue 
>> --------------------------6525413b2350e313 
>> Content-Disposition: form-data; name="entity_document"; filename="file1510059b5200f" 
>> Content-Type: application/json 
>> 

>> { 
>>  "FolderId": "a0a1300000ZG7u3", 
>>  "Name": "test.png" 
>> } 

>> 
>> --------------------------6525413b2350e313 
>> Content-Disposition: form-data; name="Body"; filename="file151001ac96950" 
>> Content-Type: image/png 
>> 

>> ‰PNG 
>> 

>> 
>> --------------------------6525413b2350e313-- 

<- HTTP/1.1 400 Bad Request 

за исключением имени файла в первой части, это довольно близко к желаемому выходу, но Salesforce возвращает сообщение:

content(req) 

[[1]] 
[[1]]$message 
[1] "Cannot include more than one binary part" 

[[1]]$errorCode 
[1] "INVALID_MULTIPART_REQUEST" 

Я пытался только с JSON, но получить немного другой Bad Request:

body <- list(entity_document= json, 
      Body = upload_file(media, type = "image/png")) 

-> Content-Type: multipart/form-data; boundary=------------------------ecbd3787f083e4b1 
-> 
<- HTTP/1.1 100 Continue 
>> --------------------------ecbd3787f083e4b1 
>> Content-Disposition: form-data; name="entity_document" 
>> 
>> { 
>>  "FolderId": "a0a1300000ZG7u3", 
>>  "Name": "test.png" 
>> } 
>> --------------------------ecbd3787f083e4b1 
>> Content-Disposition: form-data; name="Body"; filename="file151001ac96950" 
>> Content-Type: image/png 
>> 

>> ‰PNG 
>> 

>> 
>> --------------------------ecbd3787f083e4b1-- 

content(req) 

[[1]] 
[[1]]$message 
[1] "Multipart message must include a non-binary part" 

[[1]]$errorCode 
[1] "INVALID_MULTIPART_REQUEST" 

углубиться в детали, то мне кажется, что локон либо читает и отправляет файл метаданных в виде двоичного файла, если я использую upload_file или вывешивает в JSON без типа содержимого, если я его в качестве символа. Это единственная проблема? И если да, есть ли способ изменить обработчик, чтобы принять тип контента?

Любая помощь очень ценится!

ответ

0

Вот (временное) решение, основанное на @ последние дополнения Йерун к curl (см Github issue для справки):

library(curl) #>=2.4 on Cran 
library(httr) 
library(jsonlite) 

url <- "https://[Salesforce Instance]/services/data/v39.0/sobjects/Document/" 
header <- add_headers(c(Authorization = "Bearer [Salesforce Key]")) 

path <- tempfile() 
png(path, width = 800, height = 600) 
plot(cars) 
dev.off() 

media <- upload_file(path) 

x <- data.frame(Name=basename(path),ParentId="[Salesforce Parent ID]",Description="",IsPrivate=FALSE) 
x <- as.character(toJSON(unbox(x),pretty=T)) 
metadata <- form_data(x,"application/json") #new curl function to handle a character body with defined type 

body <- list(metadata=metadata,Body=media) 

req <- httr:::request(fields=body) 
req <- httr:::request_build("POST",url,req,header) 

response <- httr:::request_perform(req,new_handle()) 

я положил в request для httr, чтобы включить эту новую обработку и предположил бы, что это будет быть более простым в использовании, то есть простым POST(url,header,body=body), как только они доберутся до него.

Надеюсь, это поможет!

Смежные вопросы