熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

HttpClient模擬登錄12306購票網站

2013-11-23 18:52:56  來源: Java核心技術 

  首先網站前綴為https:// 表明是用SSL加密
   
    用HttpClient去模擬發送請求時對於URL用為https先要解決證書問題有兩種解決方案
   
    a使證書被信任
   
    在查找相關資料時對於這種方法有點麻煩最後就沒有去嘗試有興趣的朋友可以試試
   
    b使用httpClient時不檢測服務器證書是否可信
   
    擴展HttpClient 類實現自動接受證書因為這種方法自動接收所有證書因此存在一定的安全問題所以在使用這種方法前請仔細考慮您的系統的安全需求
   
具體的步驟如下
   
    ?提供一個自定義的socket factory (testMySecureProtocolSocketFactory )這個自定義的類必須實現接口
   
    mons 在實現接口的類中調用自定義的
   
    XTrustManager(testMyXTrustManager)
   
    ?創建一個mons 的實例指定協議名稱和默認的端口號
   
    Protocol myhttps = new Protocol(https new MySecureProtocolSocketFactory ()
   
    ?注冊剛才創建的https 協議對象
   
    ProtocolregisterProtocol(https myhttps)
   
具體代碼如下
   
    package teorticketutil; 
   
    import javaioIOException;
   
    import InetAddress;
   
    import InetSocketAddress;
   
    import Socket;
   
    import SocketAddress;
   
    import UnknownHostException;
   
    import javasecurityKeyManagementException;
   
    import javasecurityNoSuchAlgorithmException;
   
    import javasecuritycertCertificateException;
   
    import javasecuritycertXCertificate;
   
   
   
    import SocketFactory;
   
    import sslSSLContext;
   
    import sslTrustManager;
   
    import sslXTrustManager;
   
   
   
    import mons;
   
    import mons;
   
    import mons

    

   /**

    * MySecureProtocolSocketFactoryjavajava Create on 下午::

    * 

    * 

    * Copyright (c) by MTA

    * 

    * @author lmeteor

    * @Email

    * @description 自定義的socket factory 實現自動接受證書

    * @version   */

   public class MySecureProtocolSocketFactory implements

   SecureProtocolSocketFactory

   {

   

    private SSLContext sslcontext = null;

   

   private SSLContext createSSLContext() 

  

   SSLContext sslcontext = null;

    try

   {

   sslcontext = SSLContextgetInstance(SSL
   
    sslcontextinit(null new TrustManager[]
   
    { new TrustAnyTrustManager() } new javasecuritySecureRandom())
   
    }
   
    catch (NoSuchAlgorithmException e)
   
    {
   
    eprintStackTrace()
   
    }
   
    catch (KeyManagementException e)
   
    {
   
    eprintStackTrace()
   
    }
   
    return sslcontext;
   
    }  
   
    private SSLContext getSSLContext()
   
    {
   
    if (thissslcontext == null)
   
    {
   
    thissslcontext = createSSLContext()
   
    }
   
    return thissslcontext;
   
    }  
   
    public Socket createSocket(Socket socket String host int port
   
    boolean autoClose) throws IOException UnknownHostException
   
    {
   
    return getSSLContext()getSocketFactory()createSocket(socket host
   
    port autoClose)
   
    }  
   
    public Socket createSocket(String host int port) throws IOException
   
    UnknownHostException
   
    {
   
    return getSSLContext()getSocketFactory()createSocket(host port)
   
    }  
   
    public Socket createSocket(String host int port InetAddress clientHost
   
    int clientPort) throws IOException UnknownHostException
   
    {
   
    return getSSLContext()getSocketFactory()createSocket(host port
   
    clientHost clientPort)
   
    }  
   
    public Socket createSocket(String host int port InetAddress localAddress
   
    int localPort HttpConnectionParams params) throws IOException
   
    UnknownHostException ConnectTimeoutException
   
    {
   
    if (params == null)
   
    {
   
    throw new IllegalArgumentException(Parameters may not be null
   
    }
   
    int timeout = paramsgetConnectionTimeout()
   
    SocketFactory socketfactory = getSSLContext()getSocketFactory()
   
    if (timeout ==
   
    {
   
    return socketfactorycreateSocket(host port localAddress
   
    localPort)
   
    }
   
    else
   
    {
   
    Socket socket = socketfactorycreateSocket()
   
    SocketAddress localaddr = new InetSocketAddress(localAddress
   
    localPort)
   
    SocketAddress remoteaddr = new InetSocketAddress(host port)
   
    socketbind(localaddr)
   
    nnect(remoteaddr timeout)
   
    return socket;
   
    }
   
    }
   
    // 自定義私有類
   
    private static class TrustAnyTrustManager implements XTrustManager
   
    {
   
    public void checkClientTrusted(XCertificate[] chain String authType)
   
    throws CertificateException
   
    {
   
    }
   
    public void checkServerTrusted(XCertificate[] chain String authType)
   
    throws CertificateException
   
    {
   
    }
   
    public XCertificate[] getAcceptedIssuers()
   
    {
   
    return new XCertificate[]
   
    {};
   
    }
   
    } }
   


下面的是httpClient的具體實現類
   
    package teorticketutil; 
   
    import javaioBufferedInputStream;  import javaioFile;  import javaioFileOutputStream;  import javaioIOException;  import javaioInputStream;  import javaioUnsupportedEncodingException;  import javautilArrayList; import javautilList;   import mons; import mons; import mons; import mons; import mons; import mons;   /**   * HttpDoPostUtilsjava Create on 下午::   *    *    * Copyright (c) by MTA   *    * @author lmeteor   * @Email   * @description 模擬HTTP發送請求得到報文   * @version   */ @SuppressWarnings(deprecation public class HttpDoPostUtils {  
   
   
   
    private static HttpClient httpClient = null;
   
   
   
    static
   
    {
   
    //指定協議名稱和默認的端口號
   
    Protocol myhttps = new Protocol(https new MySecureProtocolSocketFactory()
   
    //注冊剛才創建的https 協議對象
   
    ProtocolregisterProtocol(https myhttps) 
   
    httpClient = new HttpClient()
   
    }
   
   
   
    /**
   
    * 發送請求報文得到響應報文
   
    * @param url
   
    *
   
    登錄請求URL
   
    * @param pList
   
    *
   
    是否包含請求參數
   
    * @return
   
    * @throws UnsupportedEncodingException
   
    */
   
    public static String doRequestToString(String urlList<NameValuePair> pList) throws UnsupportedEncodingException
   
    {
   
    //獲得postMethod對象
   
    PostMethod pmethod = getPostMethod(url)
   
    pmethodgetParams()setParameter(HttpMethodParamsHTTP_CONTENT_CHARSET utf
   
    //判斷是否包含參數
   
    if(null != pList && pListsize() >
   
    {
   
    pmethodsetRequestBody(pListtoArray(new NameValuePair[pListsize()]))
   
    }
   
    String value ;
   
    try
   
    {
   
    (pmethod)
   
    value = pmethodgetResponseBodyAsString()
   
    }
   
    catch ( HttpException e )
   
    {
   
    eprintStackTrace()
   
    }
   
    catch ( IOException e )
   
    {
   
    eprintStackTrace()
   
    }
   
   
   
    return value;
   
    }
   
   
   
    /**
   
    * 獲得網站的登錄驗證碼
   
    * @param url
   
    *
   
    請求URL
   
    * @param filePath
   
    *
   
    驗證碼保存路徑 如e:\\loginjpg
   
    * @return
   
    */
   
    public static File doGetFile(String urlString filePath)
   
    {
   
    PostMethod pmethod = getPostMethod(url)
   
    pmethodgetParams()setParameter(HttpMethodParamsHTTP_CONTENT_CHARSET utf
   
    try
   
    {
   
    (pmethod)
   
    //得到響應中的流對象
   
    InputStream in = pmethodgetResponseBodyAsStream()
   


    //包裝 並讀出流信息
   
    BufferedInputStream bis = new BufferedInputStream(in)
   
    File file = new File(filePath)
   
    FileOutputStream fs = new FileOutputStream(file)
   
    byte[] buf = new byte[];
   
    int len = bisread(buf)
   
    if(len == || len == ){
   
    filedelete()
   
    file = null;
   
    }
   
    while (len != ) {
   
    fswrite(buf len)
   
    len = bisread(buf)
   
    }
   
    fsflush()
   
    fsclose()
   
    return file;
   
    }
   
    catch (HttpException e)
   
    {
   
    eprintStackTrace()
   
    }
   
    catch (IOException e)
   
    {
   
    eprintStackTrace()
   
    }
   
    return null;
   
   
   
    }
   
   
   
    public static List<NameValuePair> createNameValuePair(String params) {
   
    List<NameValuePair> nvps = new ArrayList<NameValuePair>()
   
    if (null != params && !paramstrim()equals()) {
   
    String[] _params = paramssplit(&
   
    // userCookieList = new AttributeList()
   
    for (int i = ; i < _paramslength; i++) {
   
    int _i = _params[i]indexOf(=
   
    if (_i != ) {
   
    String name = _params[i]substring( _i)
   
    String value = _params[i]substring(_i +
   
    nvpsadd(new NameValuePair(name value))
   
    }
   
    }
   
    }
   
    return nvps;
   
    }
   
   
   
   
   
    public static PostMethod getPostMethod(String url)
   
    {
   
    PostMethod pmethod = new PostMethod(url)
   
    //設置響應頭信息
   
    pmethodaddRequestHeader(Connection keepalive
   
    pmethodaddRequestHeader(CacheControl maxage=
   
    pmethodaddRequestHeader(UserAgent Mozilla/ (compatible; MSIE ; Windows NT
   
    pmethodaddRequestHeader(Accept text/htmlapplication/xhtml+xmlapplication/xml;q=*/*;q=
   
    return pmethod;
   
    }
   
    }
   
    模擬請求的類已經出來現在開始進行模擬登錄登錄前必須知道自身是怎樣提交請求並包含哪些參數到後台通過firebug就很容易找到這些東西了
   
    登錄之前會調用後台返回一串JSON報文如下
   
    {loginRand:randError:Y}
   
    當randError為Y才對表單FORM提交並且將loginRand的值初始化到表單裡的隱藏域中作為參數傳到後台
   
    現在最後一步就是拼接參數了具體操作代碼如下
   
    package teorticketutil;   import javaioBufferedReader; import javaioInputStreamReader; import javaioUnsupportedEncodingException;   import teorticketdomainLoginBeforeValidatior;   import netsfjsonJSONObject; /**  * Loginjavajava Create on 下午::   *   *   * Copyright (c) by MTA  *   * @author lmeteor  * @Email   * @description   * @version   */ public class Login {
   
   
   
    /**
   
    * 獲取驗證碼
   
    * @param filePath
   
    * @return
   
    */
   
    public static String getRandCode(String filePath)
   
    {
   
    String randCode = ;
   


    /** 獲取驗證碼 */
   
    HttpDoPostUtilsdoGetFile(PropertiesUtilsnewInstance()getPropertiesValue(loginCodefilePath)
   
    randCode = readString(請輸入登錄驗證碼
   
    return randCode;
   
    }
   
   
   
    /**
   
    * 實現登錄操作
   
    * @throws UnsupportedEncodingException
   
    */
   
    public static void doLogin() throws UnsupportedEncodingException
   
    {
   
    String randCode = getRandCode(e:\\loginjpg
   
    /** 登錄前 提交得到報文 */
   
    String loginBeforeVal = HttpDoPostUtilsdoRequestToString(PropertiesUtilsnewInstance()getPropertiesValue(loginBeforeValidatiorUrlnull)
   
    //將返回的JSON報文轉換成指定的對象
   
    JSONObject jsonObj = JSONObjectfromObject(loginBeforeVal)
   
    LoginBeforeValidatior loginBefore = new LoginBeforeValidatior()
   
    loginBefore = (LoginBeforeValidatior) JSONObjecttoBean(jsonObj LoginBeforeValidatiorclass)
   
    //拼接參數
   
    StringBuffer params = new StringBuffer()
   
    paramsappend(loginRand=+loginBeforegetLoginRand())append(&
   
    append(refundLogin=Nappend(&
   
    append(refundFlag=Yappend(&
   
    append(loginUseruser_name=+PropertiesUtilsnewInstance()getPropertiesValue(username))append(&
   
    append(nameErrorFocus=&
   
    append(userpassword=+PropertiesUtilsnewInstance()getPropertiesValue(password))append(&
   
    append(passwordErrorFocus=&
   
    append(randCode=+randCode)append(&
   
    append(randErrorFocus=
   
    //像服務器發送登錄請求 並返回對應的報文
   
    String loginResponseText = HttpDoPostUtilsdoRequestToString(PropertiesUtilsnewInstance()getPropertiesValue(loginUrlHttpDoPostUtilscreateNameValuePair(paramstoString()))
   
    Systemoutprintln(loginResponseText)
   
   
   
    }
   
   
   
   
   
    /**
   
    * 多控制台讀取驗證碼
   
    * @param msg
   
    * @return
   
    * @throws Exception
   
    */
   
    private static String readString(String msg)
   
    {
   
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(Systemin))
   
    try{
   
    Systemoutprint(msg+:
   
    return bufferedReaderreadLine()
   
    }catch(Exception e){
   
    }
   
    return ;
   
    }
   
   
   
    public static void main(String[] args) throws UnsupportedEncodingException
   
    {
   
    //Login login = new Login()
   
    //logindoLogin()
   
    LogindoLogin()
   
    } }
   
    URL都是在配置文件中的大致如下
   
    #登錄之前調用URL loginBeforeValidatiorUrl= #登錄驗證碼的地址 loginCode= #登錄URL loginUrl= #用戶名 username=xxxx #密碼 password=xxx
   
    通過返回的HTML如果看到自己的名字就說明登錄成功了如果大家還想做什麼動作就可以發揮大家的想像力了


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25921.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.