selenium利用executeScript执行Post
问题场景:
同事使用htmlunit发送post请求(负载json)请求一个预期json数据,返回始终和预期不一致;
问题分析过程:
使用httpclient进行post请求,header中直接附加浏览器中的cookie和其他,content-type未设置时http状态500,content-type设置后状态204,初步判断可能是有连接session相关的判断;
使用selenium,设置Headless为false,进行目标网站登录操作,然后由于selenium没有直接post的方法,所以使用executeScript发送相关请求
String js= "function getRet(){\r\n" + " var datas = null;\r\n" + " XXX.doPost({\r\n" + " async:false,\r\n" + " url:'目标地址',\r\n" + " data:{json负载},\r\n" + " success : function(datass){\r\n" + " datas = datass;\r\n" + " }\r\n" + " });\r\n" + " return datas;\r\n" + "}\r\n" + "return getRet();"; Object ret = (Object)jsExecutor.executeScript(js);
结果符合预期
3.同事使用的是htmlunit
由于目标网站的登录会跳转sso域然后返回存在多次重定向,
设置webClient.getOptions().setRedirectEnabled(true);
HtmlPage retPage = button.click(); Thread.sleep(10000);//区别于synchronized (homePage) {homePage.wait(25000);}和client.waitForBackgroundJavaScript(30000) //由于存在多次重定向,这个等待是必要的 PrintStream originalOut = System.out; PrintStream fileOut = new PrintStream("./out111.txt"); System.setOut(fileOut); System.out.println(((HtmlPage) webClient.getCurrentWindow().getEnclosedPage()).asXml());//获取当前页面而不使用前面的Page变量,因为存在多次重定向 System.setOut(originalOut);
经过修改后,第一步的日志结果符合预期,第二步post请求
1.使用htmlunit的post
WebRequest requestSettings = new WebRequest(url, HttpMethod.POST) requestSettings.setAdditionalHeader("Content-Type","application/json"); requestSettings.setAdditionalHeader("Accept", "application/json"); requestSettings.setRequestBody(param);
由于和登录共用的一个webclient对象,就没必要设置cookie头了;
测试结果,始终返回一个不符合预期的html结果
2.使用executeJavaScript获取,
js最后的return需要修改为JSON.stringify(getRet()),
ScriptResult result = ((HtmlPage) webClient.getCurrentWindow().getEnclosedPage()).executeJavaScript(js);//使用当前页,即登录跳转最终页 Thread.sleep(10000);//需不需要等待,没有测试 Object rt = result.getJavaScriptResult(); fileOut = new PrintStream("./out222.txt"); System.setOut(fileOut); System.out.println(rt.toString()); System.setOut(originalOut);
结果符合预期
/*-------------------------------------------------------------------------------------------*/
后面我又采用httpclient的方式继续做了测试, 前面说到可能是有连接session相关的判断,那么考虑 登录和post共用一个httpclient和httpcontent,
CloseableHttpClient httpClient = HttpClients.createDefault(); CookieStore cookieStore = new BasicCookieStore(); HttpContext httpContext = new BasicHttpContext(); httpContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); DoLoginD(httpClient,"xxx",Base64.decode("xxxxx"),httpContext);//使用同一个httpclient和httpContext RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(2*5000) .setConnectionRequestTimeout(2*5000) .setSocketTimeout(2*5000) .setRedirectsEnabled(true) .build(); HttpPost request = new HttpPost(url); request.setConfig(requestConfig); request.setHeader("Accept", "application/json, text/plain, */*"); //, text/javascript, */*; q=0.01 request.setHeader("Content-Type","application/json;charset=utf-8"); StringEntity postStr = new StringEntity(postBody,ContentType.APPLICATION_JSON);//这个ContentType.APPLICATION_JSON需要尤为注意,前面204很大程度是这个没设置的问题 request.setEntity(postStr); HttpResponse response = httpClient.execute(request,httpContext); if(response.getStatusLine().getStatusCode() == 200){ HttpEntity entity = response.getEntity(); if (entity != null) { long len = entity.getContentLength(); if (len != -1 && len < 2048) result = EntityUtils.toString(entity); else { StringBuffer sb = new StringBuffer(1024 * 512); BufferedReader in = new BufferedReader( new InputStreamReader(entity.getContent(), encoding)); String line = null; while ((line = in.readLine()) != null) { sb.append(line); } result = sb.toString(); } System.out.println("Fetched data length: " + (result.length() / 1000) + " KB"); EntityUtils.consume(entity); } } else { System.out.println("response code"+response.getStatusLine().getStatusCode()); HttpEntity entity = response.getEntity(); String test = EntityUtils.toString(entity); System.out.println(test); }
反思:
前面的204的原因应该主要就是ContentType.APPLICATION_JSON未设置导致的;
参考:
https://stackoverflow.com/questions/12059278/how-to-post-json-request-using-apache-httpclient
- 点赞
- 收藏
- 关注作者
评论(0)