我们到底能走多远系列(41)

扯淡:

  好久没总结点东西了,技术上没什么总结,感觉做事空牢牢的。最近也比较疲惫。

  分享些东西,造福全人类~

主题:

1,java模拟发起一个http请求

使用HttpURLConnection,可以通过setRequestProperty方法来设置http header的内容。
/**
* post请求
* @param strUrl
* @param content
* @param charset
* @return
*/
public static String sendPost(String strUrl, String content, String charset) {
URL httpurl = null;
HttpURLConnection httpConn = null;
String returnStr = "";
PrintWriter outs = null;
try {
httpurl = new URL(strUrl);
httpConn = (HttpURLConnection) httpurl.openConnection();
httpConn.setRequestMethod( "POST"); // 默认是post
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在 http正文内,因此需要设为true, 默认情况下是false;
httpConn.setDoOutput( true);
// 设置是否从httpUrlConnection读入,默认情况下是true;
httpConn.setDoInput( true);
httpConn.setRequestProperty( "Content-Type", "text/xml");
outs = new PrintWriter(httpConn.getOutputStream());
outs.print(content);
outs.flush();
outs.close();
// 字节流 读取全部内容 包括换行符
returnStr = inputStreamToString(httpConn.getInputStream(), charset);
} catch (Exception e) {
log.error( "执行HTTP Post请求" + strUrl + "时,发生异常!" , e);
if(outs != null){
outs.close();
outs = null;
}
return returnStr;
} finally {
if (httpConn != null)
httpConn.disconnect();
if(outs != null){
outs.close();
outs = null;
}
}
return returnStr;
} public static String inputStreamToString(InputStream in,String encoding) throws Exception{
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[ BUFFER_SIZE];
int count = -1;
while((count = in.read(data,0, BUFFER_SIZE)) != -1)
outStream.write(data, 0, count);
in.close();
data = null;
return new String(outStream.toByteArray(),encoding);
}
 
在下面的代码中,我们单独分了一个inputStreamToString方法来读取请求响应的内容。
这里使用了ByteArrayOutputStream来读取,可以读取response的body的完整内容,不会丢失换行,这个要注意一下。比如我们使用BufferedReader,代码会类似于这样:
            String line, result = "";
BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "utf-8" ));
while ((line = in. readLine()) != null) {
result += line + "\n";
}
in.close();
为了不丢掉换行,需要自己拼接"\n",还有这地方还有个问题,那就是在循环中使用“+”来拼接字符串的问题,性能不行。参考:参考
 
也可以使用HttpClient 来发送post请求,感受下:
public static String sendPost(String url, Map<String, String> params,
String charset) {
StringBuffer response = new StringBuffer();
HttpClient client = new HttpClient();
HttpMethod method = new PostMethod(url);
method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
method.setRequestHeader("Cookie", "special-cookie=value");
method.setRequestHeader("", "");
// 设置Http Post数据
if (params != null) {
HttpMethodParams p = new HttpMethodParams();
for (Map.Entry<String, String> entry : params.entrySet()) {
p.setParameter(entry.getKey(), entry.getValue());
}
method.setParams(p);
}
try {
client.executeMethod(method);
if (method.getStatusCode() == HttpStatus.SC_OK) {
BufferedReader reader = new BufferedReader(
new InputStreamReader(method.getResponseBodyAsStream(),
charset));
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
}
} catch (IOException e) {
log.error("执行HTTP Post请求" + url + "时,发生异常!", e);
} finally {
method.releaseConnection();
}
return response.toString();
}

2,模拟登录微信公众平台

  既然我们可以模拟post请求,那么理论上我们也可以模拟登录,一般来说登录的过程就是发起一个post请求,把账号密码发送给服务器,服务器验证通过后,在resopnse里写cookies,然后跳转页面,接下来和服务器的交互就要基于cookies了。
那么我们要做的就是发起一个请求,然后把成功返回的cookies保存起来,每次后续需要登录状态才能和服务器交互的操作都带上cookies 。关于cookies
 
  其实就是这么个过程:
    client ---post请求---> server 
    client <--返回cookies--server
    client -请求带cookies--server
  首先,登录的请求是这样的:
  
  我们还可以注意到header中有一个Referer, 也是很有意思的,它的意思是这个请求来自于哪里。这个可以做统计啊,限制啊什么的。虽然我们可以模拟,哈哈。但是很多正规的网站都会用这个东西。有兴趣可以了解下~

  代码类似如下:

public final static String REFERER_H = "Referer";

private LoginResult _login(String username, String pwd) {
LoginResult loginResult = new LoginResult();
try {
PostMethod post = new PostMethod(LOGIN_URL);
post.setRequestHeader("Referer", "https://mp.weixin.qq.com/");
post.setRequestHeader(USER_AGENT_H, USER_AGENT);
NameValuePair[] params = new NameValuePair[] {
new NameValuePair("username", username),
new NameValuePair("pwd", DigestUtils.md5Hex(pwd
.getBytes())), new NameValuePair("f", "json"),
new NameValuePair("imagecode", "") };
post.setQueryString(params);
int status = client.executeMethod(post);
if (status == HttpStatus.SC_OK) {
String ret = post.getResponseBodyAsString();
LoginJson retcode = JSON.parseObject(ret, LoginJson.class);
// System.out.println(retcode.getRet());
if ((retcode.getBase_resp().getRet() == 302 || retcode
.getBase_resp().getRet() == 0)) {
loginResult.setCookie(client.getState().getCookies());
StringBuffer cookie = new StringBuffer();
// 处理cookies
for (Cookie c : client.getState().getCookies()) {
cookie.append(c.getName()).append("=")
.append(c.getValue()).append(";");
cookiemap.put(c.getName(), c.getValue());
}
loginResult.setCookiestr(cookie.toString());
loginResult.setToken(getToken(retcode.getRedirect_url()));
loginResult.setLogin(true);
return loginResult;
}else{
loginResult.setLogin(false);
return loginResult;
}
}
} catch (Exception e) {
String info = "【登录失败】【发生异常:" + e.getMessage() + "】";
System.err.println(info);
log.debug(info);
log.info(info);
return loginResult;
}
return loginResult;
}

  全部代码已经共享出来了:github  希望能帮到你~

3,重定向问题

  面试中是不是曾经也被问到过:forword和redirect的区别。

  网上的回答也有很多了,回过头来再看看这个问题。其实forword,可以说是服务器发起一个请求,访问自身应用下的资源。因为是服务器自己发起的,所以先前由客户端传递过来的参数就可以保持住了,而且是把访问的这个内部资源返回的内容作为客户端最初请求的响应,所以浏览器的url不会变。

  那么redirect的原理:其实是服务端在接到客户端请求后,在响应中的header中加上了一个location的东西,这个东西的原理又是:

  当浏览器接受到头信息中的 Location: xxxx 后,就会自动跳转到 xxxx 指向的URL地址,这点有点类似用 js 写跳转。但是这个跳转只有浏览器知道,不管体内容里有没有东西,用户都看不到。例:header("Location: http://www.xker.com/");也就是说redirect他的实现也依赖了浏览器的机制配合的。
  那么这样就明白了,先回一个带有location的响应,然后浏览器自己发起一个新的向location下的值的请求。因为是浏览器自己发起的请求,所以第一次发起的请求中的参数就不能保持,而因为是一个新的请求,所以浏览器的url会改变。
  还可以知道,在带有location的响应中,HTTP STATUS CODE 还是302。
  这也许是更深一点的理解吧~
 
 

  

让我们继续前行

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不会成功。

关于java发起http请求的更多相关文章

  1. 如何使用HttpClient包实现JAVA发起HTTP请求?

    今天在搭建公司项目框架的时候,发现缺少了一个Java发送HTTP请求的工具类,在网上找了一通,经过自己的改造,已经能实现get请求和post请求的了,现在将代码贴在这里.给大家参考. 1 packag ...

  2. 用Java发起HTTP请求与获取状态码(含状态码列表)

    转自:https://blog.csdn.net/xyw591238/article/details/51072697 在使用Java请求Web程序比如访问WebService接口时,通常需要先判断访 ...

  3. java发起HTTP请求的共用类

    一定要注意编码,请求时,content-type里的编码,仅仅是流的编码,而结果的编码类型,则是流转化为字符串是需要设定的. 以下是3种使用get/post的方式: import java.io.Bu ...

  4. [Java] 两种发起POST请求方法,并接收返回的响应内容的处理方式

    1.利用apache提供的commons-httpclient-3.0.jar包 代码如下: /** * 利用HttpClient发起POST请求,并接收返回的响应内容 * * @param url ...

  5. java中两种发起POST请求,并接收返回的响应内容的方式  (转)

    http://xyz168000.blog.163.com/blog/static/21032308201162293625569/ 2.利用java自带的java.net.*包下提供的工具类 代码如 ...

  6. MySQL_(Java)【事物操作】使用JDBC模拟银行转账向数据库发起修改请求

    MySQL_(Java)使用JDBC向数据库发起查询请求 传送门 MySQL_(Java)使用JDBC向数据库中插入(insert)数据 传送门 MySQL_(Java)使用JDBC向数据库中删除(d ...

  7. MySQL_(Java)使用JDBC向数据库发起查询请求

    MySQL_(Java)使用JDBC向数据库发起查询请求 传送门 MySQL_(Java)使用JDBC创建用户名和密码校验查询方法 传送门 MySQL_(Java)使用preparestatement ...

  8. 在本地开启了代理,postman可以正常发起外部请求,但Java代码却请求失败,已解决

    在本地开启了代理,postman可以正常发起外部请求,但Java代码却请求失败,已解决 现象:开了vpn访问公司服务器,postman可以正常发起服务器请求,但是java代码请求失败,连接超时.包括在 ...

  9. 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装

    微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...

随机推荐

  1. ANGULAR JS PROMISE使用

    Promise是一种模式,以同步操作的流程形式来操作异步事件,避免了层层嵌套,可以链式操作异步事件. 我们知道,在编写javascript异步代码时,callback是最最简单的机制,可是用这种机制的 ...

  2. NSSet基础-初始化、获取元素、集合运算等

    代码: #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepo ...

  3. 常见JS(JavaScript)冲突解决方法

    1.一般JS冲突解决办法 a.最容易出现的就是js的命名冲突 ①.变量名冲突 变量有全局变量和局部变量当全局变量变量和局部变量名称一致时,就会js冲突,由于变量传递数值或地址不同就会产生JavaScr ...

  4. NOIP2005 篝火晚会 解题报告

    佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”.在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会.一共有n个同学,编号从1到n.一开始,同学们按照1,2,… ...

  5. ng-repeat的group

     http://blog.csdn.net/violet_day/article/details/17023219 一.obj包含 <!doctype html> <html ng- ...

  6. 详解centos用户&组权限&添加删除用户

    1.Linux用户操作系统 Linux操作系统是多用户多任务操作系统,包括用户账户和组账户两种: 细分用户账户(普通用户账户,超级用户账户)除了用户账户以为还有组账户所谓组账户就是用户账户的集合,ce ...

  7. 图书馆管理系统SRS

    1.任务概述 1.1目标 主要提供图书信息和读者基本信息的维护以及借阅等功能.本系统是提高图书管理工作的效率,减少相关人员的工作量,使学校的图书管理工作真正做到科学.合理的规划,系统.高效的实施. 1 ...

  8. python遍历文件夹下的文件

    在读文件的时候往往需要遍历文件夹,python的os.path包含了很多文件.文件夹操作的方法.下面列出: os.path.abspath(path) #返回绝对路径 os.path.basename ...

  9. php获取远程文件大小

    获取本地文件大小filesize()就可以了,但是如何获取远程文件的大小呢? 这里介绍三个方法来获取远程文件的大小. 方法1:get_headers <?php get_headers($url ...

  10. Oracle Data Integrator与OWB的集成及迁移

    v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...