将多部分表单发布到Bamboo API

问题描述 投票:11回答:3

我在通过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内容类型:多部分/表单数据;边界= ---- BambooHR-MultiPart-Mime-边界----内容长度:520

------ BambooHR-MultiPart-Mime-Boundary ----内容处置:表格数据; name =“ category”

112------ BambooHR-MultiPart-Mime-Boundary ----内容处置:表格数据; name =“ fileName”

readme.txt------ BambooHR-MultiPart-Mime-Boundary ----内容处置:表格数据; name =“ share”

是------ BambooHR-MultiPart-Mime-Boundary ----内容处置:表格数据; name =“文件”; filename =“ readme.txt”内容类型:文本/纯文本

这是示例文本文件。

------ BambooHR-MultiPart-Mime-Boundary ------

vb.net post .net-4.5 multipartform-data
3个回答
3
投票

[在其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中找到


1
投票

我怀疑至少您的Content-Length: 520是错误的。内容长度仅适用于他们的示例。

不管怎么说,我已经很长时间没有编写VB.Net了,但是通过快速测试,这段代码的修改后的版本可以与我的REST服务配合使用,因此它应该可以在您的情况下使用,也许有些小调整。

我的测试控制台项目使用.Net 4.6.1,但可能会与某些早期的.Net Frameworks一起运行。

Imports System.IO
Imports System.Net.Http

Module Module1

    Sub Main()
        Call UploadFileToWebsite(14, "no", "D:\Temp\file.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


0
投票

是否有人愿意分享有关从BambooHR下载用户文档的代码段?我可以打电话查看与用户关联的每个文件返回的xml,但是我无法使下载正常工作。

我正在尝试找到一种为每个用户导出数据的方法。

先谢谢您。

© www.soinside.com 2019 - 2024. All rights reserved.