Advertisement
Guest User

WinHTTPRequest AutoHotkey

a guest
Aug 26th, 2018
265
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ; WinHttpRequest.ahk
  2. ;   v1.05 (2017-09-07) - 增加 DetectCharset 选项
  3. ;   v1.04 (2017-08-29) - 增加自动使用响应头的编码
  4. ;   v1.03 (2016-01-18) - 增加“加载 gzip.dll 失败”提示,防止忘记复制 gzip.dll 到脚本目录。
  5. ;   v1.02 (2015-12-26) - 修复在 XP 系统中解压 gzip 数据失败的问题。
  6. ;   v1.01 (2015-12-07)
  7.  
  8. /*
  9.     用法:
  10.         WinHttpRequest( URL, ByRef In_POST__Out_Data="", ByRef In_Out_HEADERS="", Options="" )
  11.     --------------------------------------------------------------------------------------------
  12.     参数:
  13.         URL               - 网址
  14.        
  15.         In_POST__Out_Data - POST数据/返回数据。
  16.                             若该变量为空则进行 GET 请求,否则为 POST
  17.                            
  18.         In_Out_HEADERS    - 请求头/响应头(多个请求头用换行符分隔)
  19.        
  20.         Options           - 选项(多个选项用换行符分隔)
  21.  
  22.             NO_AUTO_REDIRECT - 禁止自动重定向
  23.             Timeout: 秒钟    - 超时(默认为 30 秒)
  24.             Proxy: IP:端口   - 代理
  25.             Codepage: XXX    - 代码页。例如 Codepage: 65001
  26.             Charset: 编码    - 字符集。例如 Charset: UTF-8
  27.             SaveAs: 文件名   - 下载到文件
  28.             Compressed       - 向网站请求 GZIP 压缩数据,并解压。
  29.                               (需要文件 gzip.dll -- http://pan.baidu.com/s/1pKqKTzt)
  30.             Method: 请求方法 - 可以为 GET/POST/HEAD 其中的一个。
  31.                                这个选项可以省略,除非你需要 HEAD 请求,或者 POST 数据为空时强制使用 POST。
  32.             DetectCharset    - 如果响应头没有包含编码,则继续从网页源码中检测
  33.     --------------------------------------------------------------------------------------------
  34.     返回:
  35.         成功返回 -1, 超时返回 0, 无响应则返回为空
  36.     --------------------------------------------------------------------------------------------
  37.     清除 Cookies 的方法:
  38.         WinHttpRequest( [] )
  39.     --------------------------------------------------------------------------------------------
  40.     示例:
  41.         例1 - GET
  42.             url := "https://www.baidu.com/"
  43.  
  44.             WinHttpRequest(url, ioData := "", ioHdr := "")
  45.             ; 也可以简单写成 WinHttpRequest(url, ioData),
  46.             ; 但是一定要确保 ioData 为空,不然是进行 POST,而不是 GET
  47.  
  48.             MsgBox, % ioData
  49.  
  50.         例2 - POST
  51.             url := "https://www.baidu.com/"
  52.             postData := "key=value&key2=value2"
  53.             reqHeaders =
  54.             (LTrim
  55.                 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:42.0) Gecko/20100101 Firefox/42.0
  56.                 Referer: https://www.baidu.com
  57.             )
  58.             WinHttpRequest(url, ioData := postData, ioHdr := reqHeaders)
  59. */
  60. WinHttpRequest( URL, ByRef In_POST__Out_Data="", ByRef In_Out_HEADERS="", Options="" )
  61. {
  62.     static nothing := ComObjError(0) ; 禁用 COM 错误提示
  63.     static oHTTP   := WinHttpRequest_Init()
  64.     static oADO    := ComObjCreate("adodb.stream")
  65.  
  66.     If IsObject(URL) ; 如果第一个参数是数组,则重新创建 WinHttp 对象,以便清除 Cookies
  67.         Return oHTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
  68.  
  69.     ; 打开 URL
  70.     If (In_POST__Out_Data != "") || InStr(Options, "Method: POST")
  71.         oHTTP.Open("POST", URL, True)
  72.     Else If InStr(Options, "Method: HEAD")
  73.         oHTTP.Open("HEAD", URL, True)
  74.     Else
  75.         oHTTP.Open("GET", URL, True)
  76.  
  77.     ; 解析请求头
  78.     If In_Out_HEADERS
  79.     {
  80.         In_Out_HEADERS := Trim(In_Out_HEADERS, " `t`r`n")
  81.         Loop, Parse, In_Out_HEADERS, `n, `r
  82.         {
  83.             If !( _pos := InStr(A_LoopField, ":") )
  84.                 Continue
  85.  
  86.             Header_Name  := SubStr(A_LoopField, 1, _pos-1)
  87.             Header_Value := SubStr(A_LoopField, _pos+1)
  88.  
  89.             If (  Trim(Header_Value) != ""  )
  90.                 oHTTP.SetRequestHeader( Header_Name, Header_Value )
  91.         }
  92.     }
  93.  
  94.     If (In_POST__Out_Data != "") && !InStr(In_Out_HEADERS, "Content-Type:")
  95.         oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
  96.  
  97.     ; 解析选项
  98.     If Options
  99.     {
  100.         Loop, Parse, Options, `n, `r
  101.         {
  102.             If ( _pos := InStr(A_LoopField, "Timeout:") )
  103.                 Timeout := SubStr(A_LoopField, _pos+8)
  104.             Else If ( _pos := InStr(A_LoopField, "Proxy:") )
  105.                 oHTTP.SetProxy( 2, SubStr(A_LoopField, _pos+6) )
  106.             Else If ( _pos := InStr(A_LoopField, "Codepage:") )
  107.                 oHTTP.Option(2) := SubStr(A_LoopField, _pos+9)
  108.         }
  109.  
  110.         oHTTP.Option(6) := InStr(Options, "NO_AUTO_REDIRECT") ? 0 : 1
  111.  
  112.         If InStr(Options, "Compressed")
  113.             oHTTP.SetRequestHeader("Accept-Encoding", "gzip, deflate")
  114.     }
  115.  
  116.     If (Timeout > 30)
  117.         oHTTP.SetTimeouts(0, 60000, 30000, Timeout * 1000)
  118.  
  119.     ; 发送请求
  120.     oHTTP.Send(In_POST__Out_Data)
  121.     retCode := oHTTP.WaitForResponse(Timeout ? Timeout : -1)
  122.  
  123.     ; 自动检测编码
  124.     If !InStr(Options, "Charset:") {
  125.         if InStr(oHTTP.GetResponseHeader("Content-Type"), "charset=utf-8")
  126.             Options .= "`n" . "Charset: UTF-8"
  127.         else if !InStr(Options, "Compressed") && InStr(Options, "DetectCharset") {
  128.             if RegExMatch(oHTTP.ResponseText, "i)<meta [^>]*?http-equiv=['""]Content-Type['""] [^>]*?charset=UTF-8")
  129.                 Options .= "`n" . "Charset: UTF-8"
  130.         }
  131.     }
  132.  
  133.     ; 处理返回结果
  134.     If InStr(Options, "Compressed")
  135.     && (oHTTP.GetResponseHeader("Content-Encoding") = "gzip") {
  136.         body := oHTTP.ResponseBody
  137.         size := body.MaxIndex() + 1
  138.  
  139.         VarSetCapacity(data, size)
  140.         DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(body), "ptr*", pdata)
  141.         DllCall("RtlMoveMemory", "ptr", &data, "ptr", pdata, "ptr", size)
  142.         DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(body))
  143.  
  144.         size := GZIP_DecompressBuffer(data, size)
  145.  
  146.         ; 不可以直接 ComObjValue(oHTTP.ResponseBody)!
  147.         ; 需要先将 oHTTP.ResponseBody 赋值给变量,如 body,然后再 ComObjValue(body)。
  148.         ; 直接 ComObjValue(oHTTP.ResponseBody) 会导致在 XP 系统无法获取 gzip 文件的未压缩大小。
  149.  
  150.         If InStr(Options, "SaveAs:") {
  151.             RegExMatch(Options, "i)SaveAs:[ \t]*\K[^\r\n]+", SavePath)
  152.             FileOpen(SavePath, "w").RawWrite(&data, size)
  153.         } Else {
  154.             RegExMatch(Options, "i)Charset:[ \t]*\K[\w-]+", Encoding)
  155.             In_POST__Out_Data := StrGet(&data, size, Encoding)
  156.  
  157.             if !Encoding && InStr(Options, "DetectCharset") {
  158.                 if RegExMatch(In_POST__Out_Data, "i)<meta [^>]*?http-equiv=['""]Content-Type['""] [^>]*?charset=UTF-8")
  159.                     In_POST__Out_Data := StrGet(&data, size, "UTF-8")
  160.             }
  161.         }
  162.     }
  163.     Else If InStr(Options, "SaveAs:")
  164.     {
  165.         RegExMatch(Options, "i)SaveAs:[ \t]*\K[^\r\n]+", SavePath)
  166.  
  167.         oADO.Type := 1 ; adTypeBinary = 1
  168.         oADO.Open()
  169.         oADO.Write( oHTTP.ResponseBody )
  170.         oADO.SaveToFile( SavePath, 2 )
  171.         oADO.Close()
  172.  
  173.         In_POST__Out_Data := ""
  174.     }
  175.     Else If InStr(Options, "Charset:")
  176.     {
  177.         RegExMatch(Options, "i)Charset:[ \t]*\K[\w-]+", Encoding)
  178.  
  179.         oADO.Type     := 1 ; adTypeBinary = 1
  180.         oADO.Mode     := 3 ; adModeReadWrite = 3
  181.         oADO.Open()
  182.         oADO.Write( oHTTP.ResponseBody )
  183.         oADO.Position := 0
  184.         oADO.Type     := 2 ; adTypeText = 2
  185.         oADO.Charset  := Encoding
  186.         In_POST__Out_Data := IsByRef(In_POST__Out_Data) ? oADO.ReadText() : ""
  187.         oADO.Close()
  188.     }
  189.     Else
  190.         In_POST__Out_Data := IsByRef(In_POST__Out_Data) ? oHTTP.ResponseText : ""
  191.    
  192.     In_Out_HEADERS := "HTTP/1.1 " oHTTP.Status " " oHTTP.StatusText "`n" oHTTP.GetAllResponseHeaders()
  193.  
  194.     Return retCode ; 成功返回 -1, 超时返回 0, 无响应则返回为空
  195. }
  196.  
  197. WinHttpRequest_Init() {
  198.     if !whr := ComObjCreate("WinHttp.WinHttpRequest.5.1") {
  199.         MsgBox, 48, 错误, 创建 WinHttp.WinHttpRequest.5.1 对象失败!程序将退出。`n`n请下载 winhttp.dll 保存到 Windows 目录,并进行注册。
  200.         ExitApp
  201.     } else {
  202.         return whr
  203.     }
  204. }
  205.  
  206. GZIP_DecompressBuffer( ByRef var, nSz ) { ; 'Microsoft GZIP Compression DLL' SKAN 20-Sep-2010
  207. ; Decompress routine for 'no-name single file GZIP', available in process memory.
  208. ; Forum post :  www.autohotkey.com/forum/viewtopic.php?p=384875#384875
  209. ; Modified by Lexikos 25-Apr-2015 to accept the data size as a parameter.
  210.  
  211. ; Modified version by tmplinshi
  212. static hModule, _
  213. static GZIP_InitDecompression, GZIP_CreateDecompression, GZIP_Decompress
  214.      , GZIP_DestroyDecompression, GZIP_DeInitDecompression
  215. If !hModule {
  216.     If !hModule := DllCall("LoadLibrary", "Str", "gzip.dll", "Ptr")
  217.     {
  218.         Gui, +OwnDialogs
  219.         if !FileExist("gzip.dll") {
  220.             MsgBox, 48, 提示, 缺少文件 gzip.dll!程序将退出。
  221.         } else {
  222.             MsgBox, 48, 错误, 加载 gzip.dll 失败!程序将退出。
  223.         }
  224.         ExitApp
  225.     }
  226.        
  227.     For k, v in ["InitDecompression","CreateDecompression","Decompress","DestroyDecompression","DeInitDecompression"]
  228.         GZIP_%v% := DllCall("GetProcAddress", Ptr, hModule, "AStr", v, "Ptr")
  229.        
  230.     if !GZIP_Decompress {
  231.         Gui, +OwnDialogs
  232.         MsgBox, 48, 错误, gzip.dll 版本不匹配。`n`n详细信息: 无法从 gzip.dll 找到 Decompress 函数。`n`n程序将退出。
  233.         ExitApp
  234.     }
  235. }
  236.  
  237.  vSz :=  NumGet( var,nsz-4 ), VarSetCapacity( out,vsz,0 )
  238.  DllCall( GZIP_InitDecompression )
  239.  DllCall( GZIP_CreateDecompression, UIntP,CTX, UInt,1 )
  240.  If ( DllCall( GZIP_Decompress, UInt,CTX, UInt,&var, UInt,nsz, UInt,&Out, UInt,vsz
  241.     , UIntP,input_used, UIntP,output_used ) = 0 && ( Ok := ( output_used = vsz ) ) )
  242.       VarSetCapacity( var,64 ), VarSetCapacity( var,0 ), VarSetCapacity( var,vsz,32 )
  243.     , DllCall( "RtlMoveMemory", UInt,&var, UInt,&out, UInt,vsz )
  244.  DllCall( GZIP_DestroyDecompression, UInt,CTX ),  DllCall( GZIP_DeInitDecompression )
  245. Return Ok ? vsz : 0
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement