vba 如何向可能重定向到登录页面的页面发出 POST 请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/891427/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 10:26:35  来源:igfitidea点击:

How to make a POST request to a page that may redirect to a login page

vbapostoutlook-vbawinhttp

提问by MGOwen

I am using a macro in Outlook VBA to submit a file via POST to a URL:

我在 Outlook VBA 中使用宏通过 POST 将文件提交到 URL:

Set http = New WinHttp.WinHttpRequest
http.Open "POST", UrlToPostTo, False    'True                                          '
http.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
http.setRequestHeader "Content-Type", "multipart/form-data; "
http.Send data

My problem is the page that will accept the request (a file upload page, in this case) is protected by authentication - the initial request for it above will return a login page instead of the page itself.

我的问题是接受请求的页面(在这种情况下是文件上传页面)受身份验证保护 - 上面的初始请求将返回登录页面而不是页面本身。

I have tried to detect if the login page appears and if so, post the username and password as form variables (I'm hoping this is equivalent to a human typing said username and password into a page in the web browser).

我试图检测登录页面是否出现,如果出现,将用户名和密码作为表单变量发布(我希望这相当于人类在网络浏览器的页面中输入用户名和密码)。

So the steps are:
* request URL (include file with post).
* Check if the reponse is the login page.
* If so, then in the same http session, submit the username and password to the URL.
* If the server now processes the original post, good, otherwise I can post it again.

所以步骤是:
* 请求 URL(包含帖子的文件)。
* 检查响应是否为登录页面。
* 如果是,则在同一个http会话中,提交用户名和密码到URL。
* 如果服务器现在处理原始帖子,很好,否则我可以再次发布。

The code looks like:

代码如下:

' if the login page comes back, send credentials                                     '
If (InStr(http.ResponseText, "j_password") > 0) Then

    Dim loginData As String
    loginData = "j_username=theusername&j_password=thepassword"

    http.Open "POST", UrlToPostTo, False
    http.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
    http.setRequestHeader "Content-Type", "multipart/form-data; "
    http.Send loginData
End If

But when I do this, The http.Responsetext is just the login page still (or again?).

但是当我这样做时,http.Responsetext 仍然只是登录页面(或再次?)。

Any idea what I'm doing wrong? Is my plan even valid?

知道我做错了什么吗?我的计划是否有效?

(This is related to trying to solve this problem)

(这与试图解决这个问题有关

回答by Michael Chad

I know this thread is ancient and I realize the OP most definitely moved on long ago. I just spent the better part of 3 evenings being humbled by this exact same problem, and this thread kept coming up when I would stop to research more so I thought I would contribute for the next guy who comes along.

我知道这个线程很古老,而且我意识到 OP 肯定在很久以前就开始了。我只是在 3 个晚上的大部分时间里都被这个完全相同的问题所困扰,当我停下来进行更多研究时,这个线程不断出现,所以我想我会为下一个出现的人做出贡献。

The trick is:

诀窍是:

  • Disable redirects using using the Optionproperty, to stop it from moving on without you. (see comments below)
  • Capture the redirect on the output of the Statusproperty, and handle from there.
  • 使用Option属性禁用重定向,以阻止它在没有您的情况下继续前进。(见下方评论)
  • 捕获Status属性输出的重定向,并从那里处理。

I'm sure there's other ways, but this seemed pretty elegant to me, and I found lots of other ways to use it.

我敢肯定还有其他方法,但这对我来说似乎很优雅,而且我找到了很多其他方法来使用它。

To use the OPs code example, you could make your request as planned with one exception: The EnableRedirects var, which must come after opening the connection (didn't read that anywhere, just couldn't get it to stick to a closed connection).

要使用 OP 代码示例,您可以按计划发出请求,但有一个例外:EnableRedirects 变量,它必须在打开连接后出现(没有在任何地方读取,只是无法让它坚持关闭的连接) .

Good luck "next guy"!

祝“下一个男人”好运!

    Dim http As WinHttp.WinHttpRequest
    Dim UrlToPostTo As String, UrlRedirectedTo As String

    'Your initial request (assuming lots here)
    Set http = New WinHttp.WinHttpRequest
    http.Open "POST", UrlToPostTo, False
    'Stop it from redirecting automatically, so you can capture it
    http.Option(WinHttpRequestOption_EnableRedirects) = False 'You can also use the collection index instead of the pretty name
    http.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
    http.setRequestHeader "Content-Type", "multipart/form-data; "
    http.Send

    'Now if you have an active session, you should get your desired content
    'If it redirected you, you'll have a different status, header etc...    

    If http.status = "302" Then
        Dim loginData As String
        'Now lets find out where we're being pointed and POST there
        'This may not be the same url you see in your address bar 
        UrlRedirectedTo = http.GetResponseHeader("Location")
        'Also, you may have to do this again to arrive back at the intended resource    
        loginData = "j_username=theusername&j_password=thepassword"
        http.Open "POST", UrlRedirectedTo, False
        http.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
        http.setRequestHeader "Content-Type", "multipart/form-data; "
        http.Send loginData
    End If

Some info I found useful in the MSDN maze.

我在 MSDN 迷宫中发现一些有用的信息。

WinHttpRequest Options (MSDN)

WinHttpRequest 选项 (MSDN)

WinHttpRequest Object (MSDN)

WinHttpRequest 对象 (MSDN)

Cookie Handling WinHttp (MSDN)

Cookie 处理 WinHttp (MSDN)

回答by barrowc

Is the logon page at the same URL as the page you originally submitted to? I don't see any code that changes urlToPostTo

登录页面与您最初提交的页面的 URL 是否相同?我没有看到任何更改的代码urlToPostTo

After your first send, you might want to look at the Statusproperty of your request. See the RFCfor what each status code means. It could also help to use the GetAllResponseHeadersmethod to work out exactly what's going on. See MSDNfor more on that

第一次发送后,您可能需要查看Status请求的属性。有关每个状态代码的含义,请参阅RFC。它还可以帮助使用该GetAllResponseHeaders方法准确地确定正在发生的事情。有关更多信息,请参阅MSDN

回答by Shayne Paterson

It might be possible for you to store the username and password in cookies which would allow you to access your page directly.

您可以将用户名和密码存储在 cookie 中,这样您就可以直接访问您的页面。

    Dim doc As WinHttp.WinHttpRequest
    Set doc = New WinHttpRequest

    doc.Open "POST", url, False

    doc.SetRequestHeader "Cookie", "UserID=" & username
    doc.SetRequestHeader "Cookie", "Password=" & password

You need to confirm the variable names on your server. You can use a tool like ieHTTPHeadersto inspect the headers when you access the page from the browser to see what you need to do.

您需要确认服务器上的变量名称。当您从浏览器访问页面时,您可以使用ieHTTPHeaders 之类的工具检查标头以查看您需要执行的操作。

回答by thdoan

Try SetCredentials-- it may work for you, e.g.:

试试SetCredentials——它可能对你有用,例如:

http.Open "POST", UrlToPostTo, False
http.SetCredentials "YourUsername", "YourPassword", 0
http.Send

Source: http://www.automateexcel.com/2005/02/11/excel_vba_winhttprequest_with_login_and/

来源:http: //www.automateexcel.com/2005/02/11/excel_vba_winhttprequest_with_login_and/