部分表单到Bamboo API
我在通过VB.NET控制台应用程序向BambooHR API提交多部分表单时遇到了很多困难。 我已经发布了我的当前代码以及下面的文档中的示例请求,当我运行此代码时,我得到(400)错误的请求。 我知道代码很混乱,但我一直试图让它工作。
我能够通过使用他们的示例代码来实现GET请求,但他们没有任何代码来执行此特定的API调用(上传员工文件)。
任何帮助,将不胜感激。
这是我的代码:
Sub Main()
upload(id, "https://api.bamboohr.com/api/gateway.php/company")
Console.WriteLine()
Console.WriteLine("Press ENTER to quit")
Console.ReadLine()
End Sub
Function upload(ByVal employeeId As Integer, ByVal baseUrl As String)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or SecurityProtocolType.Ssl3
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Dim url = String.Format("{0}/v1/employees/{1}/files/", baseUrl, employeeId)
Dim request As HttpWebRequest = WebRequest.Create(url)
request.KeepAlive = True
request.Method = "POST"
request.ContentType = "multipart/form-data; boundary=" + boundary
'Authorization is just the api key and a random string, in this case is x
'
Dim authInfo As String = api_key + ":" + "x"
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo))
request.Headers("Authorization") = "Basic " + authInfo
Dim memStream As New MemoryStream()
WriteMPF(memStream)
request.ContentLength = memStream.Length
Using requestStream = request.GetRequestStream()
memStream.Position = 0
Dim tempBuffer As Byte() = New Byte(memStream.Length - 1) {}
memStream.Read(tempBuffer, 0, tempBuffer.Length)
memStream.Close()
requestStream.Write(tempBuffer, 0, tempBuffer.Length)
End Using
Dim webresponse As HttpWebResponse = request.GetResponse()
Return webresponse
End Function
Private Sub WriteMPF(s As Stream)
WriteToStream(s, "POST /api/gateway.php/company/v1/employees/id/files/ HTTP/1.0")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Host: api.bamboohr.com")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Type: multipart/form-data; boundary=----BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Length: 520")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""category""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "14")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""fileName""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "test.txt")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""share""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "no")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""file""; filename = ""test.txt""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Type: text/plain")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "this is a test!")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary------")
WriteToStream(s, vbCr & vbLf)
End Sub
Private Sub WriteToStream(s As Stream, txt As String)
Dim bytes As Byte() = Encoding.UTF8.GetBytes(txt)
s.Write(bytes, 0, bytes.Length)
End Sub
以下是来自文档的示例请求:(链接:https://www.bamboohr.com/api/documentation/employees.php向下滚动到“上传员工文件”)
POST /api/gateway.php/sample/v1/employees/1/files/ HTTP / 1.0主机:api.bamboohr.com内容类型:multipart / form-data; 边界= ---- BambooHR-MultiPart-Mime-Boundary ----内容长度:520
------ BambooHR-MultiPart-Mime-Boundary ----内容配置:form-data; NAME = “类别”
112 ------ BambooHR-MultiPart-Mime-Boundary ---- Content-Disposition:form-data; NAME = “文件名”
readme.txt ------ BambooHR-MultiPart-Mime-Boundary ---- Content-Disposition:form-data; NAME = “分享”
yes ------ BambooHR-MultiPart-Mime-Boundary ---- Content-Disposition:form-data; NAME = “文件”; filename =“readme.txt”Content-Type:text / plain
这是一个示例文本文件。
------ BambooHR-多部分MIME-边界------
在他们的GitHub上使用php示例并将其复制到VB.NET。 这有点混乱,但它有效。 这里是相关的代码:
Public Function sendRequestMPF(ByVal req As BambooHTTPRequest, ByVal fileLocation As String) As BambooHTTPResponse
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or SecurityProtocolType.Ssl3
Dim request As HttpWebRequest = WebRequest.Create(req.url)
request.Method = req.method
request.Host = "api.bamboohr.com"
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Try
request.ContentType = "multipart/form-data; boundary=" + boundary
request.ContentLength = req.contents.Length
Catch ex As Exception
End Try
Dim iCount As Integer = req.headers.Count
Dim key As String
Dim keyvalue As String
Dim i As Integer
For i = 0 To iCount - 1
key = req.headers.Keys(i)
keyvalue = req.headers(i)
request.Headers.Add(key, keyvalue)
Next
Dim enc As System.Text.UTF8Encoding = New System.Text.UTF8Encoding()
Dim bytes() As Byte = {}
Dim pdfBytes() As Byte = {}
Dim lBytes() As Byte = {}
Dim fBytes() As Byte = {}
Dim s As New MemoryStream()
If (req.contents.Length > 0) Then
bytes = enc.GetBytes(req.contents)
s.Write(bytes, 0, bytes.Length)
pdfBytes = File.ReadAllBytes(fileLocation)
s.Write(pdfBytes, 0, pdfBytes.Length)
Dim postHeader = vbCrLf + vbCrLf + "--" + boundary + "--" + vbCrLf
Dim postHeaderBytes() As Byte = enc.GetBytes(postHeader)
lBytes = enc.GetBytes(postHeader)
s.Write(postHeaderBytes, 0, postHeaderBytes.Length)
fBytes = s.ToArray()
request.ContentLength = fBytes.Length
End If
request.AllowAutoRedirect = False
If Not basicAuthUsername.Equals("") Then
Dim authInfo As String = basicAuthUsername + ":" + basicAuthPassword
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo))
request.Headers("Authorization") = "Basic " + authInfo
End If
If req.contents.Length > 0 Then
Dim outBound As Stream = request.GetRequestStream()
outBound.Write(fBytes, 0, fBytes.Length)
End If
Dim resp As BambooHTTPResponse
Try
Dim webresponse As HttpWebResponse = request.GetResponse()
resp = New BambooHTTPResponse(webresponse)
resp.responseCode = webresponse.StatusCode
resp.headers = webresponse.Headers
Catch e As WebException
Console.WriteLine(e.Message)
If (e.Status = WebExceptionStatus.ProtocolError) Then
resp = New BambooHTTPResponse(DirectCast(e.Response, HttpWebResponse).StatusCode)
Else
resp = New BambooHTTPResponse(0)
End If
End Try
Return resp
End Function
Public Function buildMultiPart(ByVal params As NameValueCollection, ByVal boundary As String, ByVal contentType As String, ByVal name As String, ByVal fileName As String)
Dim data = ""
For Each key In params.AllKeys
data += "--" + boundary + vbCrLf
data += "Content-Disposition: form-data; name=""" + key + """"
data += vbCrLf + vbCrLf
data += params(key) + vbCrLf
Next
data += "--" + boundary + vbCr + vbLf
data += "Content-Disposition: form-data; name=""" + name + """;" + " filename=""" + fileName + """" + vbCrLf
data += "Content-Type: " + contentType + vbCrLf
data += vbCrLf
'data += fileData + vbCrLf + vbCrLf
'data += "--" + boundary + "--" + vbCrLf
Return data
End Function
Public Function uploadEmployeeFile(ByVal employeeId As Integer, ByVal fileName As String, ByVal fileLocation As String)
Dim request As New BambooHTTPRequest()
request.url = String.Format("{0}/v1/employees/{1}/files/", Me.baseUrl, employeeId)
request.method = "POST"
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Dim params = New NameValueCollection
params.Add("category", "13")
params.Add("fileName", fileName)
params.Add("share", "no")
request.contents = buildMultiPart(params, boundary, "application/pdf", "file", fileName)
Return http.sendRequestMPF(request, fileLocation)
End Function
所需的其他代码可以在他们的GitHub https://github.com/BambooHR上找到
我怀疑至少你的Content-Length: 520
是错误的。 该内容长度仅适用于他们的示例。
无论如何,我很久没有写VB.Net了,但是从一个快速测试来看,这段代码的修改版本对我的一个REST服务有效,所以它应该适用于你的情况,可能有一些小调整。
我的测试控制台项目使用.Net 4.6.1,但可能会运行一些较早的.Net框架。
Imports System.IO
Imports System.Net.Http
Module Module1
Sub Main()
Call UploadFileToWebsite(14, "no", "D:Tempfile.pdf")
Console.WriteLine("Please wait for a response from the server and then press a key to continue.")
Console.ReadKey()
End Sub
Public Sub UploadFileToWebsite(category As Integer, share As String, file As String)
Dim message = New HttpRequestMessage()
Dim content = New MultipartFormDataContent()
content.Add(New StringContent(category.ToString()), "category")
content.Add(New StringContent(share), "share")
Dim filestream = New FileStream(file, FileMode.Open)
Dim fileName = System.IO.Path.GetFileName(file)
content.Add(New StreamContent(filestream), "file", fileName)
message.Method = HttpMethod.Post
message.Content = content
message.RequestUri = New Uri("https://api.bamboohr.com/api/gateway.php/company")
Dim client = New HttpClient()
client.SendAsync(message).ContinueWith(
Sub(task)
'do something with response
If task.Result.IsSuccessStatusCode Then
Console.WriteLine("Uploaded OK.")
Else
Console.WriteLine("Upload Failed.")
End If
End Sub)
End Sub
End Module
在不相关的说明中,您也可以使用vbCrLf
而不是vbCr & vbLf
。
下一篇: How to get the real file size of a file in a multipart/form