How to make an HTTP POST web request

后端 未结 14 2802
有刺的猬
有刺的猬 2020-11-21 04:31

Canonical
How can I make an HTTP request and send some data using the POST method?

14条回答
  •  遇见更好的自我
    2020-11-21 04:53

    Here's what i use in .NET 4.8 to make a HTTP POST request. With this code one can send multiple POST requests at a time Asynchronously. At the end of each request an event is raised. And also at the end of all request another event is raised.

    The one bellow is the core class:

    Imports System.ComponentModel
    Imports System.Text.RegularExpressions
    Imports System.Timers
    Imports System.Windows.Forms
    Imports AeonLabs
    Imports AeonLabs.Environment
    Imports Newtonsoft.Json
    
    Public Class HttpDataCore
        Public Property url As String
        Public Property state As New environmentVarsCore
        Public Property errorMessage As String = ""
        Public Property statusMessage As String
        Public Property threadCount As Integer = 25
        Public Property numberOfRetryAttempts = 5
        Public Property queue As List(Of _queue_data_struct)
        Public Property queueBWorker As Integer() ' has the size of threadCount
        Public Property queueLock As New Object
        Public Property retryAttempts As New _retry_attempts
        Public Property dataStatistics As List(Of _data_statistics)
        Public Property loadingCounter As Integer
        Public Property CompletionPercentage As Integer ' value range 0-100
        Public Property IsBusy As Boolean
    
        Public Structure _queue_data_struct
            Dim vars As Dictionary(Of String, String)
            Dim filenameOrSavePath As String                  ' full address file name or full adress folder path
            Dim misc As Dictionary(Of String, String)
            Dim status As Integer                             ' -1 - completed; 0- not sent yet; 1-already sent / processing 
        End Structure
        Public Structure _retry_attempts
            Dim counter As Integer
            Dim pattern As Integer
            Dim previousPattern As Integer
            Dim errorMessage As String
        End Structure
        Public Structure _data_statistics
            Dim filesize As Double
            Dim bytesSentReceived As Double
            Dim speed As Double
        End Structure
    
        Public WithEvents RestartQueueTimer As New Timers.Timer
        Public bwDataRequest() As BackgroundWorker
    
        Public Event requestCompleted(sender As Object, requestData As String) 'TODO add misc vars
    
        Private sendToQueue As Boolean
        Public Sub New(ByVal Optional _state As environmentVarsCore = Nothing, ByVal Optional _url As String = "")
            queue = New List(Of _queue_data_struct)
            dataStatistics = New List(Of _data_statistics)
            loadingCounter = 0
            sendToQueue = False
            If _state IsNot Nothing AndAlso _url.Equals("") Then
                url = _state.ServerBaseAddr & _state.ApiServerAddrPath
            ElseIf Not _url.Equals("") Then
                url = _url
            Else
                Throw New System.Exception("Initialization err: state and url cannot be both null at same time")
            End If
    
            If _state IsNot Nothing Then
                state = _state
            End If
    
        End Sub
        Public Sub loadQueue(ByVal vars As Dictionary(Of String, String), ByVal Optional misc As Dictionary(Of String, String) = Nothing, ByVal Optional filenameOrSavePath As String = Nothing)
            Dim queueItem As New _queue_data_struct
            queueItem.vars = New Dictionary(Of String, String)
            queueItem.misc = New Dictionary(Of String, String)
    
            queueItem.vars = vars
            queueItem.status = 0
            queueItem.misc = misc
            queueItem.filenameOrSavePath = filenameOrSavePath
            queue.Add(queueItem)
        End Sub
    
        Public Sub clearQueue()
            loadingCounter = 0
            queue = New List(Of _queue_data_struct)
        End Sub
        Public Sub startRequest()
            If bwDataRequest(0) Is Nothing Then
                Throw New Exception("You need to call initialze first")
                Exit Sub
            End If
    
            'startSendQueue()
            IsBusy = True
    
            AddHandler RestartQueueTimer.Elapsed, New ElapsedEventHandler(AddressOf QueueTimerTick)
            With RestartQueueTimer
                .Enabled = True
                .Interval = 500
                .Start()
            End With
        End Sub
    
        Private Sub QueueTimerTick(ByVal sender As Object, ByVal e As ElapsedEventArgs)
            If QueuesToComplete(queue).Equals(0) And QueuesToSend(queue).Equals(0) Then
                RestartQueueTimer.Stop()
                queue = New List(Of _queue_data_struct)
                RaiseEvent requestCompleted(Me, Nothing)
                IsBusy = False
                Exit Sub
            End If
    
            If retryAttempts.counter >= numberOfRetryAttempts Then 'ToDo a retry number of attempts before quits
                Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                Dim MsgBox As messageBoxForm
                MsgBox = New messageBoxForm(retryAttempts.errorMessage & ". " & My.Resources.strings.tryAgain & " ?", My.Resources.strings.question, MessageBoxButtons.YesNo, MessageBoxIcon.Question)
                If MsgBox.ShowDialog() = DialogResult.Yes Then
                    Dim retry As _retry_attempts
                    With retry
                        .counter = 0
                        .previousPattern = -1
                        .pattern = 0
                        .errorMessage = ""
                    End With
                    retryAttempts = retry
                    startSendQueue()
                Else
                    RestartQueueTimer.Stop()
                    queue = New List(Of _queue_data_struct)
                    RaiseEvent requestCompleted(Me, Nothing)
                    IsBusy = False
                    Exit Sub
                End If
                Exit Sub
            ElseIf Not sendToQueue And QueuesToSend(queue) > 0 Then
                startSendQueue()
            End If
        End Sub
    
        Private Sub startSendQueue()
            sendToQueue = True
            While QueuesToSend(queue) > 0
                For shtIndex = 0 To threadCount
                    For i = 0 To queue.Count - 1
                        If Not bwDataRequest(shtIndex).IsBusy Then
                            SyncLock queueLock
                                If queue.ElementAt(i).status.Equals(0) Then
                                    Dim data As New _queue_data_struct
                                    data.vars = queue.ElementAt(i).vars
                                    data.status = 1
                                    data.misc = queue.ElementAt(i).misc
                                    data.filenameOrSavePath = queue.ElementAt(i).filenameOrSavePath
                                    queue(i) = data
                                    queueBWorker(shtIndex) = i
                                    dataStatistics(shtIndex) = (New _data_statistics)
    
                                    bwDataRequest(shtIndex).RunWorkerAsync(queue(i))
                                    Threading.Thread.Sleep(50)
                                End If
                            End SyncLock
                        End If
                    Next i
                Next shtIndex
            End While
            sendToQueue = False
        End Sub
    
        Public Function QueuesToSend(queue As List(Of _queue_data_struct)) As Integer
            Dim counter As Integer = 0
            For i = 0 To queue.Count - 1
                If queue(i).status.Equals(0) Then
                    counter += 1
                End If
            Next i
            Return counter
        End Function
        Public Function QueuesToComplete(queue As List(Of _queue_data_struct)) As Integer
            Dim counter As Integer = 0
            For i = 0 To queue.Count - 1
                If queue(i).status.Equals(1) Then
                    counter += 1
                End If
            Next i
            Return counter
        End Function
        Public Function QueuesMultiHash(queue As List(Of _queue_data_struct)) As Integer
            Dim counter As Integer = 0
            For i = 0 To queue.Count - 1
                If queue(i).status.Equals(1) Then
                    counter += i
                End If
            Next i
            Return counter
        End Function
    
        Public Function IsBase64String(ByVal s As String) As Boolean
            s = s.Trim()
            Return (s.Length Mod 4 = 0) AndAlso Regex.IsMatch(s, "^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None)
        End Function
    
        '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        Public Function ConvertDataToArray(key As String, fields As String(), response As String) As Dictionary(Of String, List(Of String))
            If GetMessage(response).Equals("1001") Then
                Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                errorMessage = "{'error':true,'message':'" & My.Resources.strings.errorNoRecordsFound & "'}"
                Return Nothing
            End If
            Try
                Dim jsonResult = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(response)
                If jsonResult.ContainsKey(key) Then
                    If Not jsonResult.Item(key).item(0).Count.Equals(fields.Length) Then
                        Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                        errorMessage = "{'error':true,'message':'" & My.Resources.strings.JsonFieldsMismatch & ". table(" & key & "'}"
                        Return Nothing
                    Else
                        Dim results = New Dictionary(Of String, List(Of String))
                        For k = 0 To fields.Length - 1
                            Dim fieldValues As List(Of String) = New List(Of String)
                            For i = 0 To jsonResult.Item(key).Count - 1
                                fieldValues.Add(jsonResult.Item(key).item(i).item(k).ToString)
                            Next i
                            results.Add(fields(k), fieldValues)
    
                        Next k
                        Return results
                    End If
                Else
                    Threading.Thread.CurrentThread.CurrentUICulture = Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                    errorMessage = "{'error':true,'message':'" & My.Resources.strings.JsonkeyNotFound & " (" & key & "'}"
                    Return Nothing
                End If
            Catch ex As Exception
                errorMessage = "{'error':true,'message':'" & ex.ToString & "'}"
                errorMessage = ex.ToString
                Return Nothing
            End Try
        End Function
    End Class
    

    the AeonLabs.Envoriment is a class with a collection or fields and properties.

    And the one bellow is for making a POST request:

    Imports System.ComponentModel
    Imports System.IO
    Imports System.Net
    Imports System.Text
    Imports System.Web
    Imports System.Web.Script.Serialization
    Imports System.Windows.Forms
    Imports AeonLabs.Environment
    Imports AeonLabs.Security
    
    Public Class HttpDataPostData
        Inherits HttpDataCore
    
        Public Event updateProgress(sender As Object, misc As Dictionary(Of String, String))
        Public Event dataArrived(sender As Object, requestData As String, misc As Dictionary(Of String, String))
    
        Public Sub New(ByVal Optional _state As environmentVarsCore = Nothing, ByVal Optional _url As String = "")
            MyBase.New(_state, _url)
        End Sub
        Public Sub initialize(ByVal Optional _threadCount As Integer = 0)
            If Not _threadCount.Equals(0) Then
                threadCount = _threadCount
            End If
    
            ReDim bwDataRequest(threadCount)
            ReDim queueBWorker(threadCount)
    
            For shtIndex = 0 To threadCount
                dataStatistics.Add(New _data_statistics)
    
                bwDataRequest(shtIndex) = New System.ComponentModel.BackgroundWorker
                bwDataRequest(shtIndex).WorkerReportsProgress = True
                bwDataRequest(shtIndex).WorkerSupportsCancellation = True
    
                AddHandler bwDataRequest(shtIndex).DoWork, AddressOf bwDataRequest_DoWork
                AddHandler bwDataRequest(shtIndex).RunWorkerCompleted, AddressOf bwDataRequest_RunWorkerCompleted
            Next shtIndex
            Dim retry As _retry_attempts
            With retry
                .counter = 0
                .previousPattern = -1
                .pattern = 0
                .errorMessage = ""
            End With
            retryAttempts = retry
        End Sub
    
        Private Sub bwDataRequest_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
    
            ' Find out the Index of the bWorker that called this DoWork (could be cleaner, I know)
            Dim Y As Integer
            Dim Index As Integer = Nothing
            For Y = 0 To UBound(bwDataRequest)
                If sender.Equals(bwDataRequest(Y)) Then
                    Index = Y
                    Exit For
                End If
            Next Y
    
            Dim queue As _queue_data_struct
            queue = e.Argument
    
            Dim vars As New Dictionary(Of String, String)
            vars = queue.vars
    
            'TODO translation need to be local
            If Not System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() Then
                Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                e.Result = "{'error':true,'message':'" & My.Resources.strings.errorNoNetwork & "'}"
                Exit Sub
            End If
            If vars Is Nothing Then
                e.Result = "{'error':true,'message':'missconfiguration vars'}"
                Exit Sub
            End If
    
            If Not vars.ContainsKey("id") Then
                vars.Add("id", state.userId)
            End If
            If Not vars.ContainsKey("pid") Then
                Dim appId As New FingerPrint
                vars.Add("pid", appId.Value)
            End If
            If Not vars.ContainsKey("language") Then
                vars.Add("language", state.currentLang)
            End If
            If Not vars.ContainsKey("origin") Then
                vars.Add("origin", state.softwareAccessMode)
            End If
    
            Dim serializer As New JavaScriptSerializer()
            Dim json As String = serializer.Serialize(vars)
            Dim encryption As New AesCipher(state)
            Dim encrypted As String = HttpUtility.UrlEncode(encryption.encrypt(json))
            Dim PostData = "origin=" & state.softwareAccessMode & "&data=" & encrypted
            Dim request As WebRequest = WebRequest.Create(url)
            Dim responseFromServer As String = ""
            Dim decrypted As String = ""
    
            request.Method = "POST"
            Dim byteArray As Byte() = Encoding.UTF8.GetBytes(PostData)
            request.ContentType = "application/x-www-form-urlencoded"
            request.Headers.Add("Authorization", state.ApiHttpHeaderToken & "-" & state.softwareAccessMode)
            request.ContentLength = byteArray.Length
            Try
                Dim dataStream As Stream = request.GetRequestStream()
                dataStream.Write(byteArray, 0, byteArray.Length)
                dataStream.Close()
                Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
                dataStream = response.GetResponseStream()
                Dim reader As New StreamReader(dataStream)
                responseFromServer = reader.ReadToEnd()
                reader.Close()
                dataStream.Close()
                response.Close()
    
                If response.StatusCode = HttpStatusCode.Accepted Or response.StatusCode = 200 Then
                    If IsBase64String(responseFromServer) And Not responseFromServer.Equals("") Then
                        decrypted = encryption.decrypt((responseFromServer)).Replace("\'", "'")
                    Else
                        Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                        decrypted = "{'error':true,'encrypted':false,'message':'" & My.Resources.strings.contactingCommServer & " |" & responseFromServer & "|'}"
                    End If
                Else
                    Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                    decrypted = "{'error':true,'message':'" & My.Resources.strings.contactingCommServer & " (" & response.StatusCode & ")', 'statuscode':'" & response.StatusCode & "'}"
                End If
            Catch ex As Exception
                Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo(state.currentLang)
                decrypted = "{'error':true,'message':'" & My.Resources.strings.contactingCommServer & " (" & ex.Message.ToString.Replace("'", "\'") & ")'}"
            End Try
    
            e.Result = decrypted.Replace("\'", "'")
        End Sub
    
        Private Sub bwDataRequest_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
            ' Find out the Index of the bWorker that called this DoWork (could be cleaner, I know)
            Dim Y As Integer
            Dim Index As Integer = Nothing
            Dim data As New _queue_data_struct
    
            For Y = 0 To UBound(bwDataRequest)
                If sender.Equals(bwDataRequest(Y)) Then
                    Index = Y
                    Exit For
                End If
            Next Y
    
            If IsResponseOk(e.Result, "statuscode") Then
                data = New _queue_data_struct
                data = queue(queueBWorker(Index))
                data.status = 0 're queue the file
                SyncLock queueLock
                    queue(queueBWorker(Index)) = data
                End SyncLock
                Dim errorMsg As String = GetMessage(e.Result)
                Dim retry As _retry_attempts
                With retry
                    .counter = retryAttempts.counter
                    .previousPattern = retryAttempts.previousPattern
                    .pattern = retryAttempts.pattern
                    .errorMessage = retryAttempts.errorMessage
                End With
                retry.errorMessage = If(retryAttempts.errorMessage.IndexOf(errorMsg) > -1, retryAttempts.errorMessage, retryAttempts.errorMessage & System.Environment.NewLine & errorMsg)
    
                retry.pattern = QueuesMultiHash(queue)
                If retry.previousPattern.Equals(retry.pattern) Then
                    retry.counter += 1
                Else
                    retry.counter = 1
                    retry.previousPattern = retryAttempts.pattern
                End If
    
                retryAttempts = retry
                Exit Sub
            End If
    
            data = New _queue_data_struct
            data = queue(queueBWorker(Index))
            data.status = -1 'completed sucessfully status
            SyncLock queueLock
                queue(queueBWorker(Index)) = data
            End SyncLock
    
            loadingCounter += 1
            CompletionPercentage = (loadingCounter / queue.Count) * 100
            statusMessage = "Loading data from the cloud ..."
            RaiseEvent updateProgress(Me, queue(queueBWorker(Index)).misc)
            RaiseEvent dataArrived(Me, e.Result, queue(queueBWorker(Index)).misc)
        End Sub
    End Class
    

    The Aoenlabs.Security is a class for sending POST data encrypted using standard encryption algorithms

提交回复
热议问题