关于httpclient处理图片验证码提交的问题

JavaLiver 2013-03-27 04:59:20
本人之前用httpclient 3做了个自动登录网站的程序,实现的功能为登录网站,并在另一个页面post一个请求,请求时有图片验证码。

登录功能没有问题,在后面的post之前,我先从网站用get方法获取这个最新的验证码图片,然后调用本地程序解析成正确的String,但是提交了之后还是回到这个提交页面。

我用浏览器模拟了一下这些操作,提交成功的话应该是返回302,并转到另一个page。如果是验证码错误,就会返回200,并回到提交的页面,原来的字段输入都会保存在页面上(用的应该是aspx的__VIEWSTATE和__EVENTVALIDATION)但不会提示验证码错误。
就因为网站本身不会提示验证码错误,所以我程序返回200,并回到原来的页面我就无从判断到底是什么原因,因为我在本地程序里看到的验证码的确是解析正确的。

猜测会不会是cookie的问题,但我登录之后,每次操作前都会获取一下cookie,并且在get或者post前,用httpclient再把cookie set回request里,这样跳转页面的话,session还能保持的。

或者是验证码重复刷新的问题,但是我用fiddler看过浏览器的请求过程,它先用get获取那个要提交的页面,然后会自动用get获取那个验证码,再人工点击提交form。我只不过是直接用get获取了那个验证码,然后post提交了那个页面。

也怀疑过是aspx的__VIEWSTATE和__EVENTVALIDATION,在我的post request里有这两个字段的值,每次用浏览器提交,似乎都是不变的,所以我直接写进request了。如果不包括这两个值,那么如果验证码错误的话,返回到提交页面,上面原来部分输入的字段就是空的要重新输入,所以这两个参数应该是用来记录页面信息并还原的。

请有经验的朋友指教指教,如果能解决,立马结贴,谢谢!
...全文
441 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
lzzgym 2013-10-14
  • 打赏
  • 举报
回复
网站把验证码写在cookie里??这种方式也太不安全了吧 一般的做法都是直接放在session啊。。。 最近一直在研究验证码,有兴趣交流。。。。
JavaLiver 2013-03-29
  • 打赏
  • 举报
回复
如果用一个httpclient依次做,会不会有问题? 还是说要new多个httpclient?
  • 打赏
  • 举报
回复
看着没啥问题 httpClient.getCookieStore().getCookies() 获取cookie,看看有没有set进去吧
  • 打赏
  • 举报
回复
并发问题。。
JavaLiver 2013-03-28
  • 打赏
  • 举报
回复
调试通了!!!Cookie没问题。是一个很低级的问题,这个网站通过获取另个值来判断是否实际做了操作的,而我提交的那个值的name打错了一个字母,等于没提交成功。。瀑布汗。。。。。。。。。。。 依然谢谢楼上看了我的代码,并回复。 我顺便在这里问最后个问题,如果我要同时用3个用户名登录网站,都做一遍上面这个操作,(3个依次做也可以),是不是要用3个httpclient呢?怎么实现效率较高呢?最好不要用线程,感觉太麻烦。谢谢回答!
JavaLiver 2013-03-27
  • 打赏
  • 举报
回复
上面getFinalPostMethod里面 post.setRequestBody(new NameValuePair[] { _EVENTTARGET, _EVENTARGUMENT, _VIEWSTATE, _EVENTVALIDATION, t1, t2, CheckCode, CheckCode }); 上面多输入了一个CheckCode,实际代码里是没有的。
JavaLiver 2013-03-27
  • 打赏
  • 举报
回复
HttpClient client = new HttpClient(); client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT, "http"); client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); client.getParams().setParameter(HttpMethodParams.USER_AGENT, "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko/20100101 Firefox/11.0"); HttpMethod method_post = getPostMethod(); // 使用 POST 方式提交数据 method_post.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY); client.executeMethod(method_post); method_post.releaseConnection(); String tmpcookies = GetCookies(client); GetCheckCode(client, tmpcookies); HttpMethod final_post = getFinalPostMethod(); final_post.getParams().setParameter("http.protocol.cookie-policy", CookiePolicy.BROWSER_COMPATIBILITY); tmpcookies = GetCookies(client); final_post.setRequestHeader("cookie", tmpcookies); client.executeMethod(final_post); int statuscode = final_post.getStatusCode(); if (statuscode == 200) { String response = final_post.getResponseBodyAsString(); System.out.println(response); //如果验证码错误,返回的应该是200 } if (statuscode == 302) { //如果验证码正确,并且正确提交,返回的应该是302 Header header = final_post.getResponseHeader("location"); newuri = header.getValue(); System.out.println("final_post newuri:" + newuri); if ((newuri == null) || (newuri.equals(""))) newuri = "/"; GetMethod redirect = new GetMethod(newuri); tmpcookies = GetCookies(client); redirect.setRequestHeader("cookie", tmpcookies); client.executeMethod(redirect); System.out.println("==========Final Redirect:==========\n" + redirect.getStatusLine().toString()); System.out.println(redirect.getResponseBodyAsString()); redirect.releaseConnection(); } final_post.releaseConnection(); private static HttpMethod getPostMethod() { PostMethod post = new PostMethod("/login.aspx"); NameValuePair username = new NameValuePair("name", "my name"); NameValuePair password = new NameValuePair("password", "pass"); post.setRequestBody(new NameValuePair[] { username, password}); return post; } private static HttpMethod getFinalPostMethod() { PostMethod post = new PostMethod("/finalpost.aspx?m1=100"); NameValuePair _EVENTTARGET = new NameValuePair("__EVENTTARGET", ""); NameValuePair _EVENTARGUMENT = new NameValuePair("__EVENTARGUMENT", ""); NameValuePair _VIEWSTATE = new NameValuePair( "__VIEWSTATE", "/asdfuovansodfhasdhsdfkasdf="); NameValuePair _EVENTVALIDATION = new NameValuePair( "__EVENTVALIDATION", "/sdfgsdfasdfasdf=="); NameValuePair t1 = new NameValuePair("t1", "test"); NameValuePair t2 = new NameValuePair("t2", "test@sina.com"); NameValuePair CheckCode = new NameValuePair("CheckCode", code); post.setRequestBody(new NameValuePair[] { _EVENTTARGET, _EVENTARGUMENT, _VIEWSTATE, _EVENTVALIDATION, t1, t2, CheckCode, CheckCode }); post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, "UTF-8"); post.setRequestHeader("referer","http://fortest.com.cn/finalpost.aspx?m1=100"); return post; } private static String GetCookies(HttpClient client) { String tmpcookies = ""; Cookie[] cookies = client.getState().getCookies(); for (Cookie c : cookies) { tmpcookies += c.toString() + ";"; } return tmpcookies; } public static void GetCheckCode(HttpClient client, String tmpcookies) throws HttpException, IOException { /********** Get Checkcode **********/ GetMethod getcode = new GetMethod("/getCode.aspx"); getcode.setRequestHeader("cookie", tmpcookies); client.executeMethod(getcode); System.out.println("getting code status: " + getcode.getStatusLine().toString()); InputStream inStream = getcode.getResponseBodyAsStream(); BufferedImage iag = ImageIO.read(inStream); //以下省略了较长的解析代码,弄成本地图片在本地解析,然后赋值到这个public类的String类型的code字段,code字段是在getFinalPostMethod方法中所使用到的。 }
  • 打赏
  • 举报
回复
没错误,就上代码先。
-AJ- 2013-03-27
  • 打赏
  • 举报
回复
我觉得这样的描述,不太容易找到原因。 你用httpwatch看一下。这里有范例http://www.cnblogs.com/mayingbao/archive/2007/11/30/978530.html
JavaLiver 2013-03-27
  • 打赏
  • 举报
回复
关键就是没有错误信息,我上面也提到,最后那个post的页面,我用浏览器去访问并且用错误验证码去提交的话,结果会是继续返回到这个提交页面,然后系统刷新了一下那个验证码,并不会有报错。如果我用程序去post,然后打印出200 response的结果,也是返回到这个页面,但是我用的是正确的验证码,所以有点怀疑post之后是不是系统又刷新了一下验证码,但是用wiresharp和fiddler并没有看到,也没有理由post后服务器会去调用get刷新验证码。所以怀疑cookie/session的问题,但每次我都是设置cookie了的。。。所以是不是做这种程序还有什么特别要注意的地方。 实在不行,打算用httpclient4做一下,或者模仿浏览器访问的流程,登录后先get一下这个提交页面,然后从上面拿下那个验证码图片。。。
  • 打赏
  • 举报
回复
具体错误信息。
JavaLiver 2013-03-27
  • 打赏
  • 举报
回复
顺便说一下,显示我的结贴率为0,因为这个id很久没用了,之前一直用另一个id的。这次特地上来把这个id里的分给用完。
内容: 1 转换基本数据类型;运算符;计算阶乘; 2 复数类;java的参数传递;自定义形状类;类的加载顺序;方法和变量在继承时的覆盖和隐藏;排序类; 3数字 数字类;格式化数字;转换数字进制;生成随机数; 4数组和集合 使用Arrays类;动态调整数组长度;java为数据结构中的列表定义了一个接口类java.util.list同时提供了3个实现类,分别是ArrayList、Vector、LinkedList使用; 生成不重复的随机数序列;列表、集合与数组的互相转换;java为数据结构中的映射定义一个接口java.util.Map,有四个实现类HashMap Hashtable LinkedHashMap TreeMap用法和区别;对Map排序; 5字符串 使用String;判断一个字符串是否是合法的java标识符;使用StringBuffer;IP地址转化成整数,整数转化成IP地址; 十八为身份证格式验证;表达式解析器;字符串编码的转换;字符串对齐器;密码加密和验证(MD5); 制作命令行程序;使用正则表达式操作字符串;使用正则表达式验证电话号码的格式; 6java异常处理 throw和throws、try和catch;自定义异常类;使用finally;使用异常的技巧和原则; 7 IO输入输出流 获取文件的基本信息;列出指定目录下的文件,并可过滤文件;创建文件和目录;删除文件和目录;移动文件和目录; 复制文件和目录;一个简单的文件搜索器; 多种方式读文件内容, 按字节读取文件内容、按字符读取文件内容、按行读取文件内容、随机读取文件内容; 多种方式写文件内容, 按字节写文件内容、按字符写文件内容、按行写文件内容 ; 添加内容到文件结尾;文件的分割和合并;使用StreamTokenizer统计文件的字符数; 序列化和反序列化对象(将不长用的对象暂时持久化到文件中为对象的序列化,反之用时再把对象恢复到内存为反序列化); 控制对象的序列化和反序列化; 读jar包的资源文件;用zip格式压缩 和解压文件;操作Excel文件;操作Pdf文件;自定义日志文件类; 8线程 线程的启动 和停止;线程的互斥;线程的协作;线程join;生产者、消费者问题;线程的优先级;列出虚拟机中所有的线程;守护线程Daemon;线程池;一个死锁的例子; 定时器Timer:包括在指定时间执行任务,在指定时间之后执行任务以及在某个时间之后每隔时间段重复执行的任务; 9 Java GUI 日历:使用swing和awt实现一个图形化的日历可以查询星期、日期和年份信息(CalenderTrain.java);标准计算器(Callulator.java);更改组建外观,对日历设置几个显示外观(lookandfeel.java);自定义对话框DialogWindows;制作欢迎界面SplashWindow.java; 10 java图形 一个圆形按钮,当单击按钮时颜色发生变化CircleButton.java; 捕捉屏幕相当于键盘上的PrintScreen,CsreenCaputure.java; 缩放图片JPGTransforme.java; 2d图形,实现一个2d画板,能够画2d的线、圆和矩形,能指定图形的颜色并且能够撤销和恢复图形,command.java; 3d图形,Graphic3d.java; 一个时钟程序,能够显示星期和日期,变化背景和透明度Clock.java; 11 java多媒体 滚动的消息,实现一个简单的动画,具有滚动效果的文本消息RollingMessage.java; 三维弹球,BouncingB.java; 贪吃蛇游戏SnakeModel.java; java的声音处理,介绍java中如何处理声音,包括实现响铃,播放wav,au等音频文件,以及控制声音的大小和音量,Beep.java; 媒体播放器,JMFMediaPlayer.java; 12反射 是java程序开发的特征之一,允许java程序对自身进行检查,并能直接操作程序的内部属性; instanceof操作符,instanceof.java; 获取类的信息,ViewClassInfoJrame.java; 动态调用类的方法,CallMetod.java; 13、网络编程 获取URL信息,主要是使用URLConnection类,GetUrlInfo.java; web浏览器,webbrowser.java; 获取IP地址和域名,GetIpAddress.java; Http客户端,httpClient.java; 基本socket编程,介绍socket编程的基本步骤,启动socket服务器后,在打开socket的客户端,在输入框里输入消息发送到服务器,服务器受到消息后返回给客户端; Http服务器,httpsever.java; 一个支持多线程的服务器框架,GeneralServer.java; 代理服务器,ProxyServer.java; telnet客户端,访问系统的telnet服务实质上是与telnet服务建立socket连接,默认的telnet服务的端口是23,TelnetClient.java; UDP编程,包括收发udp报文; 聊天室服务器端,Chatserver.java;聊天室客户端,ChatClient.java; Ftp客户端,Mainframe.java; 14数据库 连接各种数据库DBconnector.java; 获得数据库和表的元数据Getmetadata.java; 查询和更新数据库OperateDatadb.java; 批处理,介绍如何一次执行一批sql语句,这些sql语句用插入、更新和删除等相关操作; 提交和回滚transaction.java; 使用PreparedStatement,动态执行sql语句,UsingPreparedStatement.java; 读写二进制数据,BinaryData.java; 读写Blob数据,blob数据常以二进制形式存储比较大的文件数据,如图片、视频文件等,本文介绍如何往数据库中读写blob数据,BlobData.java; 使用ResultSet更新数据库,UpdateWithResultSet.java; 使用RowSet,.UsingRowSet.java; 调用存储过程,StorageProcedure.java; 一个数据库连接池,JDBCInfo.java; 15 applet java可以编写两类程序,applications和applet,applications可以在控制台直接运行,与其他高级编程语言没有太大区别,而java的特色在于它具有编制小应用程序的功能,applet可以在internet上传输并在兼容java的web浏览器中运行的程序; applet时钟,Clock.java; 处理鼠标和键盘,用户在applet上按下键盘时,该实列能把按下的建显示出来,点击鼠标时能把鼠标事件和鼠标坐标显示出来,MouseAndKeyapplet.java; 英文打字小游戏,TypingGame.java; applet间通信; 汉诺塔游戏, 16 j2se5.0 新特性 自动装箱和拆箱; 新的for循环; 枚举类型; 静态导入; 格式化输出; 使用ProcessBuilder执行本地命令; 泛型编程; 监控和管理虚拟机;新的线程执行架构; 线程锁; 线程条件; 线程同步装置:semaphore countdownlatch cyclicbarrier exchanger; 17 java与xml 用dom处理xml文档; 用sax处理xml文档; 用xslt转换xml; 对象与xml的转换; 18 java mail 使用smtp协议发送简单邮件; 发送带附件的邮件; 给多人发送邮件; 使用pop3接收邮件; 19jsp与servlet 获取客户端的真实ip地址; jsp无刷新聊天室; 设置和读取cookie; 上传文件; 用servlet生成图形验证码; 用servlet实现分页查看数据库;

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧