2015-11-03 42 views
1

我有一個delphi的wininet應用程序。用delphi上WININET上傳文件

上週我試圖發送信息來執行JSON方法,本週我試圖將文件上傳到Web服務器。我使用相同的代碼進行了一些修改,但在執行InternetWriteFile過程的那一刻,該程序引發了一個例外:「控制器無法使用」。

的代碼是在這裏:

function TFormMain.CargarArchivo(Archivo, Server: string; Username, Password: PChar; blnSSL, iftoken: Boolean): Boolean; 
    var 
     Url, Header : String; 
     pSession, pConnection, pRequest : HINTERNET; 
     flags, dwSize, dwFlags : DWORD; 
     dwError, Port : Integer; 
     Escritos : Cardinal; 
    begin 
     Result := false; 
     pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
     if not Assigned(pSession) then 
      raise Exception.Create('InternetOpen failed. ' + WinInetErrorMsg(GetLastError)); 
     try 
      Url := Copy(Server,pos('/Servidor',Server),length(Server)); 
      if blnSSL then 
      begin 
      Server := Copy(Server,9,pos('/Servidor',Server)-1); 
      Port := INTERNET_DEFAULT_HTTPS_PORT 
      end 
      else 
      begin 
      Server := Copy(Server,8,pos('/Servidor',Server)-1); 
      Server := Copy(Server,1,pos(':',Server)-1); 
      Port := 8080; 
      end; 
      pConnection := InternetConnect(pSession, PChar(Server), port, Username, Password, INTERNET_SERVICE_HTTP, 0, 0); 
      if not Assigned(pConnection) then 
      raise Exception.Create('InternetConnect failed. ' + WinInetErrorMsg(GetLastError)); 
      try 
      if blnSSL then 
       flags := INTERNET_FLAG_SECURE 
      else 
       flags := 0; 
      pRequest := HTTPOpenRequest(pConnection, 'POST', PChar(Url), nil, nil, nil, flags, 0); 
      if not Assigned(pRequest) then 
       raise Exception.Create('HttpOpenRequest failed. ' + WinInetErrorMsg(GetLastError)); 
      try 
       // Set buffer size 
       dwSize:=SizeOf(dwFlags); 
       // Get the current flags 
       if (InternetQueryOption(pRequest, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, dwSize)) then 
       begin 
        // Add desired flags 
        dwFlags:=dwFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_CERT_CN_INVALID or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID; 
        // Set new flags 
        if not(InternetSetOption(pRequest, INTERNET_OPTION_SECURITY_FLAGS, @dwFlags, dwSize)) then 
        begin 
         // Get error code 
         dwError:=GetLastError; 
         // Failure 
         MessageBox(Application.Handle, PChar(IntToStr(dwError)), PChar(Application.Title), MB_OK or MB_ICONINFORMATION); 
        end; 
       end 
       else 
       begin 
        // Get error code 
        dwError:=GetLastError; 
        // Failure 
        MessageBox(Application.Handle, PChar(IntToStr(dwError)), PChar(Application.Title), MB_OK or MB_ICONINFORMATION); 
       end; 
       Header := 'Host: ' + Server + ':' + IntToStr(Port) + #13#10 + 
          'Content-Type: multipart/form-data; charset=UTF-8'#13#10; 
       if iftoken then 
       begin 
        Header := Header + 'auth_token: '+token+#13#10; 
        Header := Header + 'Csrf-token: no-check'#13#10; 
       end; 

       if not HttpAddRequestHeaders(pRequest, PChar(Header), Length(Header), HTTP_ADDREQ_FLAG_ADD) then 
        raise Exception.Create('HttpAddRequestHeaders failed. ' + WinInetErrorMsg(GetLastError)); 

       Parameters := TIdMultiPartFormDataStream.Create; 
       Parameters.AddFile('archivo', Archivo, ''); 
       if not HTTPSendRequest(pRequest, nil, 0, Parameters, Parameters.Size) then 
        raise Exception.Create('HTTPSendRequest failed. ' + WinInetErrorMsg(GetLastError)); 

       try 
        if not InternetWriteFile(Parameters, Parameters, Parameters.Size, Escritos) then 
         raise Exception.Create('InternetWriteFile failed. ' + WinInetErrorMsg(GetLastError)); 
        Result := true; 
       finally 
        Parameters.Free; 
       end; 
      finally 
       InternetCloseHandle(pRequest); 
      end; 
      finally 
      InternetCloseHandle(pConnection); 
      end; 
     finally 
      InternetCloseHandle(pSession); 
     end; 
    end; 

Exception

我試圖初始化FTPOpenFile程序文件指針,但它不工作,因爲服務器是HTTP,FTP不,我猜。

回答

2

您不能以混合Indy和WinInet的方式混用它們。

您正試圖從內存直接對POST對象Indy TIdMultipartFormDataStream。這將永遠不會工作。您必須告知TIdMultipartFormDataStream從您的輸入參數生成其MIME數據,然後改爲發佈該數據。 TIdHTTTP.Post()爲你處理,但你沒有使用TIdHTTP,所以你必須手動完成。在這種情況下,您必須將生成的TIdMultipartFormDataStream數據保存到單獨的TMemoryStream(使用TStream.CopyFrom()方法),然後您可以使用WinInet發佈該數據。

即使是這樣,你POST仍然會打破,因爲:

  1. 你是不包括在你的Content-Type請求頭中需要boundary參數(TIdMultipartFormDataStream生成動態值),使服務器可以解析MIME部分正確。

  2. 如果它們都嘗試發送請求的正文數據,則不能將HTTPSendRequest()InternetWriteFile()混合在一起。挑一個或另一個。

嘗試更多的東西是這樣的:

PostData := TMemoryStream.Create; 
try 
    Parameters := TIdMultiPartFormDataStream.Create; 
    try 
    Parameters.AddFile('archivo', Archivo, ''); 
    PostData.CopyFrom(Parameters, 0); 
    Header := 'Host: ' + Server + ':' + IntToStr(Port) + #13#10 + 
       'Content-Type: ' + Parameters.RequestContentType + #13#10; 
    finally 
    Parameters.Free; 
    end;  
    if iftoken then 
    begin 
    Header := Header + 'auth_token: '+token+#13#10; 
    Header := Header + 'Csrf-token: no-check'#13#10; 
    end; 
    if not HttpAddRequestHeaders(pRequest, PChar(Header), Length(Header), HTTP_ADDREQ_FLAG_ADD) then 
    raise Exception.Create('HttpAddRequestHeaders failed. ' + WinInetErrorMsg(GetLastError)); 
    if not HTTPSendRequest(pRequest, nil, 0, PostData.Memory, PostData.Size) then 
    raise Exception.Create('HTTPSendRequest failed. ' + WinInetErrorMsg(GetLastError)); 
    Result := True; 
finally 
    PostData.Free; 
end; 
+0

再次感謝你的幫助。我在處理這個組件時真的很新鮮,我習慣於使用INDY,因此我使用了組件。 –