问题
I'm attempting to update a legacy VB6 component (not written by me) to the .NET platform. There is one function which posts an XML string to a URL:
Function PostToUrl(ByRef psUrl, ByRef psData, Byref psResponseText, ByRef psErrorMsg, ByRef psUsername, ByRef psPassword)
On Error Resume Next
Dim objWinHTTP
PostToUrl = False
psErrorMsg = ""
psResponseText = ""
Dim m_lHTTPREQUEST_SETCREDENTIALS_FOR_SERVER
m_lHTTPREQUEST_SETCREDENTIALS_FOR_SERVER =0
Set objWinHTTP = CreateObject("WinHttp.WinHttpRequest.5.1")
objWinHTTP.Open "POST", psUrl
If psUsername <> "" Then
Call objWinHTTP.SetCredentials(psUsername, psPassword, m_lHTTPREQUEST_SETCREDENTIALS_FOR_SERVER)
End If
objWinHTTP.SetRequestHeader "Host", "http://www.xxx.com/CSIHTTP.asp"
objWinHTTP.SetRequestHeader "X-Method", "Submit"
objWinHTTP.SetRequestHeader "Content-Type", "text/xml"
objwinHTTP.setTimeouts 3000, 15000, 15000, 120000
Call objWinHTTP.Send(psData)
' Handle errors '
If Err.Number <> 0 Then
psErrorMsg = Err.Description & " test"
PostToUrl = False
ElseIf objWinHTTP.Status <> 200 AND objWinHTTP.Status <> 202 Then
psErrorMsg = "(" & objWinHTTP.Status & ") " & objWinHTTP.StatusText
PostToUrl = False
Else
psErrorMsg = objWinHTTP.ResponseText & "(" & objWinHTTP.Status & ") " & objWinHTTP.StatusText
PostToUrl = True
End If
Set objWinHTTP = Nothing
End Function
I've updated this to:
Public Function PostXml(ByVal XML As String) As Boolean
Try
Dim URL As String = My.Settings.NTSPostURL
'TODO: supply username and password! '
Dim Bytes As Byte() = Me.Encoding.GetBytes(XML)
Dim HTTPRequest As HttpWebRequest = DirectCast(WebRequest.Create(Me.PostURL), HttpWebRequest)
Dim Cred As New NetworkCredential("username", "password", "http://www.xxx.com")
With HTTPRequest
.Method = "POST"
.ContentLength = Bytes.Length
.ContentType = "text/xml"
.Credentials = Cred
.Timeout = 120000
.Method = "Submit"
End With
Using RequestStream As Stream = HTTPRequest.GetRequestStream()
RequestStream.Write(Bytes, 0, Bytes.Length)
RequestStream.Close()
End Using
Using Response As HttpWebResponse = DirectCast(HTTPRequest.GetResponse(), HttpWebResponse)
If Response.StatusCode <> HttpStatusCode.OK Then
Dim message As String = [String].Format("POST failed. Received HTTP {0}", Response.StatusCode)
Throw New ApplicationException(message)
End If
End Using
Catch ex As WebException
Dim s As String = ex.Response.ToString() & " " & ex.Status.ToString()
Throw
End Try
End Function
However when I run the .NET code the server returns the error '403 Forbidden - protocol error' on the line:
Using Response As HttpWebResponse = DirectCast(HTTPRequest.GetResponse(), HttpWebResponse)
. The VB6 code runs fine. Can anyone identify any discrepancies between the two that might be causing this? It's left me stumped....
回答1:
Doesnt look like you are setting a HOST header int he .net version, unless I am missing it. If your server is using HostHeaderResolution to host multiple domains on the same ip address, then you will get a 403.
This is just a wild guess of course.
回答2:
Have you tried capturing the traffic from the two sources and comparing them?
I'd start by trying Fiddler http://www.fiddler2.com/fiddler2/ which is a free HTTP debugging proxy.
If that doesn't work you can try WireShark which is a free protocol analyzer (a bit lower level so there will be a lot of detail to filter out). http://www.wireshark.org/
回答3:
I don't think you've got the Credential thing sorted correctly. You are using the authority portion of the URL as a credential domain.
Try it like this:-
Dim myCache as New CredentialCache()
myCache.Add(New Uri("http://www.xxx.com"), "Basic", New NetworkCredential("username", "password"))
HTTPRequest.Credentials = myCache
This assumes that Basic authentication is needed, another contender would be "Digest" or "NTLM" which may require a domain. For example if the text of the username is like this "domain\username" in the old code then you would want:-
Dim myCache as New CredentialCache()
myCache.Add(New Uri("http://www.xxx.com"), "NTLM", New NetworkCredential("username", "password", "domain"))
HTTPRequest.Credentials = myCache
BTW, I agree with steamer25, for this sort of thing you really need a tool such as fiddler.
If you have an example of the old stuff working place fiddler on the machine where this code runs. Start fiddler and use the command proxycfg -u. Now you can observe the converstation the original stuff has with the ASP server. Use proxycfg -d before closing fiddler.
Now in your .NET code place the following in the app.config:-
<system.net>
<defaultProxy enabled="false">
<proxy proxyaddress="http://127.0.0.1:8888" bypassonlocal="False"/>
</defaultProxy>
</system.net>
Start fiddler and flick the enabled attribute to "true". Now you should see the conversation your new code is trying to have with the ASP Server. Make sure you set enabled="false" before using your new code without fiddler capturing.
回答4:
After much pain I've finally managed to get it working. Problem was with the text encoding, I've changed it to ASCII and it all works:
Try
Dim Bytes As Byte() = Me.Encoding.GetBytes(XML)
Dim HTTPRequest As HttpWebRequest = DirectCast(WebRequest.Create(Me.PostURL), HttpWebRequest)
With HTTPRequest
.Method = "POST"
.ContentLength = Bytes.Length
.ContentType = "text/xml"
.Credentials = New NetworkCredential("user", "password") 'myCache
End With
Using RequestStream As Stream = HTTPRequest.GetRequestStream()
RequestStream.Write(Bytes, 0, Bytes.Length)
RequestStream.Close()
End Using
Using Response As HttpWebResponse = DirectCast(HTTPRequest.GetResponse(), HttpWebResponse)
Return Response.StatusCode
End Using
Catch ex As WebException
Dim s As String = ex.Status.ToString
Throw
End Try
Thanks to all who helped. Upvotes all round.
来源:https://stackoverflow.com/questions/940237/conversion-of-vb6-http-request-to-vb-net-2-0