少年阿宾

那些青春的岁月

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

#

第一种:(Thread)

package com.abin.lee.servlet.mythread.thread;

public class Mythread extends Thread{
 private String name;
 public Mythread(String name) {
  this.name=name;
 }
 public void run() {
  synchronized(this.name){
   System.out.println("开始时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
   System.out.println("name="+name);
   System.out.println("结束时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
 
  }
 }
 
}



测试代码:

package com.abin.lee.servlet.mythread.thread;

public class MythreadTest {
 public static void main(String[] args) {
  Mythread mythread1=new Mythread("ManyThread");
  Mythread mythread2=new Mythread("ManyThread");
  mythread1.start();
  mythread2.start();
 }

}




第二种:(Runnable)

package com.abin.lee.servlet.mythread.runnable;

public class MyRunnable implements Runnable{
 private String name;
 public MyRunnable(String name) {
  this.name=name;
 }
 public synchronized void run(){
   System.out.println("开始时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
   System.out.println("name="+name);
   try {
    Thread.sleep(3000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("结束时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
 }
}




测试代码:

package com.abin.lee.servlet.mythread.runnable;

public class MyRunnableTest {
 public static void main(String[] args) {
  MyRunnable myRunnable=new MyRunnable("ManyThread");
  Thread thread1=new Thread(myRunnable);
  Thread thread2=new Thread(myRunnable);
  thread1.start();
  thread2.start();
 }
}




第三种:(Callable)这种说明一下,这个实现多线程的方式是在JDK1.5引进的,在java.util.concurrent.Callable  这个并发包下面,并且提供同步返回结果的多线程。

package com.abin.lee.servlet.mythread.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyCallable implements Callable<String>{
 private String name;
 public MyCallable(String name) {
  this.name=name;
 }
 public String call() throws Exception {
  Lock lock=new ReentrantLock();
  lock.lock();
  String result="";
  try {
   System.out.println("开始时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
   System.out.println("name="+name);
   if(name.equals("ManyThread")){
    result="success";
   }else{
    result="failure";
   }
   try {
    Thread.sleep(3000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   System.out.println("结束时间:"+System.currentTimeMillis()+",线程名字:"+Thread.currentThread().getName());
 
  } catch (Exception e) {
   e.printStackTrace();
  }finally{
   lock.unlock();
  }
     return result;  
 }
 
}




测试代码:

package com.abin.lee.servlet.mythread.callable;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.junit.Test;

public class MyCallableTest {
 @Test
 public void testMyCallable() throws InterruptedException, ExecutionException{
  ExecutorService executor=Executors.newFixedThreadPool(3);
  MyCallable myCallable=new MyCallable("ManyThread");
  Future future1=executor.submit(myCallable);
  System.out.println("future1="+future1.get());
  Future future2=executor.submit(myCallable);
  System.out.println("future2="+future2.get());
  Future future3=executor.submit(myCallable);
  System.out.println("future3="+future3.get());
  
 }

}

测试结果:

开始时间:1350056647659,线程名字:pool-1-thread-1
name=ManyThread
结束时间:1350056650661,线程名字:pool-1-thread-1
future1=success
开始时间:1350056650661,线程名字:pool-1-thread-2
name=ManyThread
结束时间:1350056653661,线程名字:pool-1-thread-2
future2=success
开始时间:1350056653662,线程名字:pool-1-thread-3
name=ManyThread
结束时间:1350056656663,线程名字:pool-1-thread-3
future3=success
posted @ 2012-10-12 23:41 abin 阅读(924) | 评论 (0)编辑 收藏

package com.abin.lee.servlet.important.type;

import java.io.Serializable;

public class LookValue implements Serializable{
 /**
  *
  */
 private static final long serialVersionUID = -7746631577693804188L;
 private int id;
 private String name;
 private transient String status;
 
 public LookValue() {
  super();
 }
 public LookValue(int id, String name, String status) {
  super();
  this.id = id;
  this.name = name;
  this.status = status;
 }
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getStatus() {
  return status;
 }
 public void setStatus(String status) {
  this.status = status;
 }
 
}





package com.abin.lee.servlet.important.type.test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

import org.junit.Test;

import com.abin.lee.servlet.important.type.LookValue;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

public class LookValueTest {
 @Test
 public void testLookValue() throws IOException, ClassNotFoundException{
  LookValue look=new LookValue();
  look.setId(1);
  look.setName("abin");
  look.setStatus("abing");
  OutputStream out=new ByteOutputStream();
  FileOutputStream file=new FileOutputStream("data.ser");
  ObjectOutputStream obj=new ObjectOutputStream(file);
  obj.writeObject(look);
  obj.flush();
  obj.close();
  
  look=null;
  FileInputStream input=new FileInputStream("data.ser");
  ObjectInputStream oin=new ObjectInputStream(input);
  look=(LookValue)oin.readObject();
  oin.close();
  System.out.println("id="+look.getId());
  System.out.println("Name="+look.getName());
  System.out.println("Status="+look.getStatus());
 }
}




输出结果:
id=1
Name=abin
Status=null
posted @ 2012-10-08 21:49 abin 阅读(747) | 评论 (0)编辑 收藏

mysql定时器是系统给提供了event,而oracle里面的定时器是系统给提供的job。废话少说,下面创建表:
create table mytable (
id int auto_increment not null,
name varchar(100) not null default '',
introduce text not null,
createtime timestamp not null,
constraint pk_mytable primary key(id)
)


创建存储过程,这里的存储过程主要提供给mysql的定时器event来调用去执行:
create procedure mypro()
BEGIN
insert into mytable (name,introduce,createtime) values ('1111','inner mongolia',now());
end;
这里只是简单的写了一下,只是为了说明例子。


紧接着创建mysql的定时器event:
create event if not exists eventJob 
on schedule every 1 second
on completion PRESERVE
do call mypro();
这里设置为每一秒执行一次


至此所有的准备工作已经写完了,做完这些,mysql要想利用定时器必须的做准备工作,就是把mysql的定时器给开启了:
SET GLOBAL event_scheduler = 1;  -- 启动定时器
SET GLOBAL event_scheduler = 0;  -- 停止定时器


紧接着还要开启事件:
ALTER EVENT eventJob ON  COMPLETION PRESERVE ENABLE;   -- 开启事件
ALTER EVENT eventJob ON  COMPLETION PRESERVE DISABLE;  -- 关闭事件


SHOW VARIABLES LIKE '%sche%'; -- 查看定时器状态


至此,你去数据库里面的表mytable里面看下,系统会每隔一秒去插入一条数据,嘻嘻,任务完成了。
select * from mytable
posted @ 2012-10-08 20:22 abin 阅读(14694) | 评论 (5)编辑 收藏

 在进行性能测试时,一般都需要对应用服务器进行监控,监控的指标包括应用服务器的JVM使用状况、可用连接数、队列长度等信息。商业的应用服务器如WebLogic、WebSphere等都提供了Console对这些指标进行监控,在性能测试时可以很容易观察这些指标的情况。

  Tomcat作为在国内得到广泛应用的J2EE服务器,在不少项目中都得到了使用。Tomcat小巧灵活、配置简单,非常适合小的WEB应用使用。但在对使用Tomcat的应用系统进行性能测试时,最头疼的问题就是不能获得应用服务器的相关性能指标数据。

  其实,从Tomcat 5.0开始,Tomcat就已经为自己提供了一个用于监控应用服务器性能指标的servelet —— status servelet。安装完Tomcat 5之后,通过访问 http://yourhost:port/manager/status 就可以获得当时的应用服务器监控数据。

  当然,为了安全起见,Tomcat 5在缺省安装时是不允许用户直接访问 http://yourhost:port/manager/status 的,访问的时候会给出一个403(forbidden)的错误信息。在Tomcat的Manual里说明了允许用户访问的方法:

   1. 转到Tomcat的安装目录下;
   2. 修改conf/tomcat-users.xml文件,在其中加入一行  <user username="servermon" password="passwd" roles="manager"/>

  这样就可以在访问 http://yourhost:port/manager/status 时给出 servermon 的用户名与口令,查看到应用服务器的相关性能指标数据。



http://java.chinaitlab.com/server/783798.html 

posted @ 2012-09-27 20:38 abin 阅读(319) | 评论 (0)编辑 收藏

实现servlet的跳转,以输入流的形式来传输数据

测试UnionPayServlet的httpClient测试类:
  package com.abin.lee.https;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import junit.framework.TestCase;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class HttpClientTest extends TestCase {
private static final String Url = "http://localhost:9090/Spa/UnionPayServlet";
@Test
public void testHttpClient() throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(Url);
ContentProducer create = new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write("start");
writer.flush();
writer.close();
}
};
HttpEntity request = new EntityTemplate(create);
post.setEntity(request);
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
System.out.println("the last message is: "+result);
}
}



//被访问的servlet,也就是中间servlet
package org.litsoft.air.servlet;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class UnionPayServlet extends HttpServlet {
private static final String Url = "http://localhost:9090/Spa/changeServlet";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("UnionPayServlet");
String result=null;
BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream()));
int num=0;
char[] buffer=new char[1024];
while((num=reader.read(buffer))!=-1){
result=new String(buffer,0,num);
}
System.out.println("from HttpCLient message is: ="+result);
final String transfer=result;
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(Url);
ContentProducer create = new ContentProducer() {
public void writeTo(OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writer.write(transfer);
writer.flush();
writer.close();
}
};
HttpEntity httpEntity = new EntityTemplate(create);
post.setEntity(httpEntity);
HttpResponse httpResponse = client.execute(post);
HttpEntity entity = httpResponse.getEntity();
String result1 = EntityUtils.toString(entity);
// System.out.println(result1);
ServletOutputStream out=response.getOutputStream();
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
writer.write("this message is received by UnionPayServlet is: "+result1);
writer.flush();
writer.close();
}
@Override
public void destroy() {
super.destroy();
}
}




//最终要处理的servlet
package org.litsoft.air.servlet;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.litsoft.air.unionpay.CreateJdomOne;
public class ChangeServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 接收Servlet传回来的信息
BufferedReader reader = new BufferedReader(new InputStreamReader(
request.getInputStream()));
String show = null;
StringBuffer stb = new StringBuffer();
while ((show = reader.readLine()) != null) {
stb.append(show);
}
System.out.println("from UnionPayServlet message is :" + stb.toString());
reader.close();
ServletOutputStream out=response.getOutputStream();
BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
writer.write("this message is received by ChangeServlet is :"+stb.toString());
writer.flush();
writer.close();
}
}


//servlet的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>UnionPayServlet</servlet-name>
<servlet-class>org.litsoft.air.servlet.UnionPayServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UnionPayServlet</servlet-name>
<url-pattern>/UnionPayServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>changeServlet</servlet-name>
<servlet-class>org.litsoft.air.servlet.ChangeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>changeServlet</servlet-name>
<url-pattern>/changeServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
posted @ 2012-09-27 20:31 abin 阅读(1830) | 评论 (0)编辑 收藏

以下文章都是整合了好多网上的好多朋友的优秀资源,才写出来的。具体参考过谁的,我也记不清楚了。关于怎么生成https双向的证书,地址在这里:
http://www.blogjava.net/stevenjohn/archive/2012/08/22/385989.html 
应该正常来说,按照这个教程做的话是没有任何问题的,但是也有些朋友出过问题,主要问题是在,把证书导入到浏览器里面的时候出的,注意这里。

我这里面的我都做过三四次了,基本没啥问题。但也不排除不会不出问题。

由于网上关于httpCilent来测试调用HTTPS的例子较少,经过在度娘和谷爹的查找,总算是也找到了一篇文章,参考以后,做出来一个测试类,在我机器上面是能够跑通的。具体地址:http://www.blogjava.net/stevenjohn/archive/2012/09/27/388646.html 



//首先说一下,这个是我随便写的一个发布到tomcat的httpsUrlConnection的Servlet服务,主要是用来测试一下https双向验证的,现在网上好多的文章都是https单向验证的Java代码,我在网上看过好多,但是好多都是半成品,然后总结了一下,在自己的机器上面是完全能够跑通的,在这里做个笔记,以后用得着的时候来拿:
package com.abin.lee.https;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class ReceiveHttpsUrlConnectionRequest extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("receive https request");
                /**这个主要是接收,由对方给以POST形式发过来的内容,这种内容不是以key-value的形式发的,而是直接通过Java的
                *string content="test https double auth";
                *BufferedWriter writer  = new BufferedWriter();
                *writer.writer(content.getBytes());
                *通过这种形式发过来的内容的接收,由于直接放到request里面发送过来的,所以的从request里面来接收。
                *之前做银联的手机支付的时候也是这么传递参数的。
                */
BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream()));
String line=null;
StringBuffer stb=new StringBuffer();
                //循环的一行一行的读取内容
     while((line=reader.readLine())!=null){
stb.append(line);
}
                //打印读取到的内容。
System.out.println("stb="+stb.toString());
                //给调用者返回内容
PrintWriter write=response.getWriter();
write.write("receive HttpsUrlConnection success");
write.flush();
write.close();
}
}




//这个是在web工程里面的web.xml里面配置的发布的servlet服务
//web.xml
<servlet>
<servlet-name>httpsUrlConnectionRequest</servlet-name>
<servlet-class>com.abin.lee.https.ReceiveHttpsUrlConnectionRequest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>httpsUrlConnectionRequest</servlet-name>
<url-pattern>/httpsUrlConnectionRequest</url-pattern>
</servlet-mapping>

//HttpsUrlConnection测试类
package com.abin.lee.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.util.Date;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import junit.framework.TestCase;
import org.junit.Before;
import org.junit.Test;
public class HttpsUrlConnectionClient extends TestCase {
// 客户端密钥库
private String sslKeyStorePath;
private String sslKeyStorePassword;
private String sslKeyStoreType;
// 客户端信任的证书
private String sslTrustStore;
private String sslTrustStorePassword;
        //上面发布的servlet请求地址
private String httpsUrlConnectionUrl = "https://localhost:8443/global/httpsUrlConnectionRequest";
@Before
public void setUp() {
                //这是密钥库
     sslKeyStorePath = "D:\\home\\tomcat.keystore";
sslKeyStorePassword = "stevenjohn";
sslKeyStoreType = "JKS"; // 密钥库类型,有JKS PKCS12等
                //信任库,这里需要服务端来新人客户端才能调用,因为这个我是配置的https双向验证,不但是要客户端信任服务端,服务端也要信任客户端。
sslTrustStore = "D:\\home\\tomcat.keystore";
sslTrustStorePassword = "stevenjohn";
System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword",
sslKeyStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
// 设置系统参数
System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
System.setProperty("javax.net.ssl.trustStorePassword",
sslTrustStorePassword);
System.setProperty("java.protocol.handler.pkgs", "sun.net.www.protocol");
}
@Test
public void testHttpsUrlConnectionClient() {
try {
URL url = new URL(httpsUrlConnectionUrl);
                        //对于主机名的验证,因为配置服务器端的tomcat.keystore的证书的时候,是需要填写用户名的,一般用户名来说是本地ip地址,或者本地配置的域名
     HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hv);
                        //编写HttpsURLConnection 的请求对象,这里需要注意HttpsURLConnection 比我们平时用的HttpURLConnection对了一个s,因为https是也是遵循http协议的,并且是采用ssl这个安全套接字来传输信息的,但是也有可能遭到黑客的攻击  
HttpsURLConnection connection = (HttpsURLConnection) url
.openConnection();
connection.setRequestProperty("Content-Type", "text/xml");
connection.setDoOutput(true);
connection.setDoInput(true);
                        //设置请求方式为post,这里面当然也可以用get,但是我这里必须用post
     connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setReadTimeout(30000);
String user="abin";
String pwd="abing";
String request="user="+user+"&pwd="+pwd;
OutputStream out = connection.getOutputStream();
                        //下面的这句话是给servlet发送请求内容
out.write(request.getBytes());
out.flush();
out.close();
//接收请求的返回值
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuffer stb = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
stb.append(line);
}
Integer statusCode = connection.getResponseCode();
System.out.println("返回状态码:" + statusCode);
reader.close();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}




//发布好了服务,你需要在tomcat里面配置好了https服务的端口才能使用。
//tomcat配置文件:
 <Connector port="6060" protocol="HTTP/1.1" 
               connectionTimeout="20000" 
               redirectPort="8443" />
        
        /**关于https端口的说明,银联一般用的都是0--9  443,这种类型的端口,第一位是0--9中的任意一位,然后后面三位是443,而通过我的测试,发觉随便一个端口号都可           *   以的,只要不和你机器的其他端口冲突就行,911,95553这些端口都是可以滴。
          *clientAuth="true"   这里设置为false是https单向认证,设置为true则是https双向认证
        */
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
  SSLEnabled="true" maxThreads="150" scheme="https"
  secure="true" clientAuth="true" sslProtocol="TLS"
  keystoreFile="D:\\home\\tomcat.keystore" keystorePass="stevenjohn"  //密钥库
  truststoreFile="D:\\home\\tomcat.keystore" truststorePass="stevenjohn" />//信任库
posted @ 2012-09-27 00:16 abin 阅读(11232) | 评论 (1)编辑 收藏

已经发布的准备要测试的https服务:
package com.abin.lee.https;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class ReceiveHttpClientRequest extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("receive https request");
Map map=request.getParameterMap();
String user=(((Object[])map.get("user"))[0]).toString();
System.out.println("user="+user);
String pwd=(((Object[])map.get("pwd"))[0]).toString();
System.out.println("pwd="+pwd);
//给调用者返回值
PrintWriter write=response.getWriter();
write.write("receive HttpClient success");
write.flush();
write.close();
}
}





//web.xml
<servlet>
<servlet-name>httpsClientRequest</servlet-name>
<servlet-class>com.abin.lee.https.ReceiveHttpClientRequest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>httpsClientRequest</servlet-name>
<url-pattern>/httpsClientRequest</url-pattern>
</servlet-mapping>




//HttpClient测试类
package com.abin.lee.test;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import junit.framework.TestCase;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.junit.Before;
import org.junit.Test;
public class HttpsClient extends TestCase {
private String httpUrl = "https://localhost:8443/global/httpsClientRequest";
// 客户端密钥库
private String sslKeyStorePath;
private String sslKeyStorePassword;
private String sslKeyStoreType;
// 客户端信任的证书
private String sslTrustStore;
private String sslTrustStorePassword;
@Before
public void setUp() {
sslKeyStorePath = "D:\\home\\tomcat.keystore";
sslKeyStorePassword = "stevenjohn";
sslKeyStoreType = "JKS"; // 密钥库类型,有JKS PKCS12等
sslTrustStore = "D:\\home\\tomcat.keystore";
sslTrustStorePassword = "stevenjohn";
System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
System.setProperty("javax.net.ssl.keyStorePassword",
sslKeyStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
// 设置系统参数
System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
System.setProperty("javax.net.ssl.trustStorePassword",
sslTrustStorePassword);
}
@Test
public void testHttpsClient() {
SSLContext sslContext = null;
try {
KeyStore kstore = KeyStore.getInstance("jks");
kstore.load(new FileInputStream(sslKeyStorePath),
sslKeyStorePassword.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance("sunx509");
keyFactory.init(kstore, sslKeyStorePassword.toCharArray());
KeyStore tstore = KeyStore.getInstance("jks");
tstore.load(new FileInputStream(sslTrustStore),
sslTrustStorePassword.toCharArray());
TrustManager[] tm;
TrustManagerFactory tmf = TrustManagerFactory
.getInstance("sunx509");
tmf.init(tstore);
tm = tmf.getTrustManagers();
sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyFactory.getKeyManagers(), tm, null);
} catch (Exception e) {
e.printStackTrace();
}
try {
HttpClient httpClient = new DefaultHttpClient();
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext);
Scheme sch = new Scheme("https", 8443, socketFactory);
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
HttpPost httpPost = new HttpPost(httpUrl);
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("user", "abin"));
nvps.add(new BasicNameValuePair("pwd", "abing"));
httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
String spt = System.getProperty("line.separator"); 
BufferedReader buffer = new BufferedReader(new InputStreamReader(
httpResponse.getEntity().getContent()));
StringBuffer stb=new StringBuffer();
String line=null;
while((line=buffer.readLine())!=null){
stb.append(line);
}
buffer.close();
String result=stb.toString();
System.out.println("result="+result);
} catch (Exception e) {
e.printStackTrace();
}
}
}







//tomcat配置文件:(前提是https双向验证证书生成的没有一点问题)

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
  SSLEnabled="true" maxThreads="150" scheme="https"
  secure="true" clientAuth="true" sslProtocol="TLS"
  keystoreFile="D:\\home\\tomcat.keystore" keystorePass="stevenjohn"
  truststoreFile="D:\\home\\tomcat.keystore" truststorePass="stevenjohn" />



posted @ 2012-09-27 00:11 abin 阅读(3196) | 评论 (0)编辑 收藏

HttpClient程序包是一个实现了 HTTP 协议的客户端编程工具包,要想熟练的掌握它,必须熟悉 HTTP协议。一个最简单的调用如下:
 
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
 
public class Test {
    public static void main(String[] args) {
 
       // 核心应用类
       HttpClient httpClient = new DefaultHttpClient();
 
        // HTTP请求
        HttpUriRequest request =
                new HttpGet("http://localhost/index.html");
 
        // 打印请求信息
        System.out.println(request.getRequestLine());
        try {
            // 发送请求,返回响应
            HttpResponse response = httpClient.execute(request);
 
            // 打印响应信息
            System.out.println(response.getStatusLine());
        } catch (ClientProtocolException e) {
            // 协议错误
            e.printStackTrace();
        } catch (IOException e) {
            // 网络异常
            e.printStackTrace();
        }
    }
}
 
如果HTTP服务器正常并且存在相应的服务,则上例会打印出两行结果:
 
    GET http://localhost/index.html HTTP/1.1
    HTTP/1.1 200 OK 
 
核心对象httpClient的调用非常直观,其execute方法传入一个request对象,返回一个response对象。使用 httpClient发出HTTP请求时,系统可能抛出两种异常,分别是ClientProtocolException和IOException。第一种异常的发生通常是协议错误导致,如在构造HttpGet对象时传入的协议不对(例如不小心将”http”写成”htp”),或者服务器端返回的内容不符合HTTP协议要求等;第二种异常一般是由于网络原因引起的异常,如HTTP服务器未启动等。
从实际应用的角度看,HTTP协议由两大部分组成:HTTP请求和HTTP响应。那么HttpClient程序包是如何实现HTTP客户端应用的呢?实现过程中需要注意哪些问题呢?
HTTP请求
 
HTTP 1.1由以下几种请求组成:GET, HEAD, POST, PUT, DELETE, TRACE and OPTIONS, 程序包中分别用HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, and HttpOptions 这几个类创建请求。所有的这些类均实现了HttpUriRequest接口,故可以作为execute的执行参数使用。
所有请求中最常用的是GET与POST两种请求,与创建GET请求的方法相同,可以用如下方法创建一个POST请求:
 
HttpUriRequest request = new HttpPost(
        "http://localhost/index.html");
 
 
HTTP请求格式告诉我们,有两个位置或者说两种方式可以为request提供参数:request-line方式与request-body方式。
request-line
 
request-line方式是指在请求行上通过URI直接提供参数。
(1)
我们可以在生成request对象时提供带参数的URI,如:
 
HttpUriRequest request = new HttpGet(
        "http://localhost/index.html?param1=value1&param2=value2");
 
(2)
另外,HttpClient程序包为我们提供了URIUtils工具类,可以通过它生成带参数的URI,如:
 
URI uri = URIUtils.createURI("http", "localhost", -1, "/index.html",
    "param1=value1&param2=value2", null);
HttpUriRequest request = new HttpGet(uri);
System.out.println(request.getURI());
 
上例的打印结果如下:
 
    http://localhost/index.html?param1=value1&param2=value2
 
(3)
需要注意的是,如果参数中含有中文,需将参数进行URLEncoding处理,如:
 
String param = "param1=" + URLEncoder.encode("中国", "UTF-8") + "&param2=value2";
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/sshsky/index.html", param, null);
System.out.println(uri);
 
上例的打印结果如下:
 
    http://localhost/index.html?param1=%E4%B8%AD%E5%9B%BD&param2=value2
 
(4)
对于参数的URLEncoding处理,HttpClient程序包为我们准备了另一个工具类:URLEncodedUtils。通过它,我们可以直观的(但是比较复杂)生成URI,如:
 
List params = new ArrayList();
params.add(new BasicNameValuePair("param1", "中国"));
params.add(new BasicNameValuePair("param2", "value2"));
String param = URLEncodedUtils.format(params, "UTF-8");
URI uri = URIUtils.createURI("http", "localhost", 8080,
"/sshsky/index.html", param, null);
System.out.println(uri);
 
上例的打印结果如下:
 
    http://localhost/index.html?param1=%E4%B8%AD%E5%9B%BD&param2=value2
 
request-body
 
与request-line方式不同,request-body方式是在request-body中提供参数,此方式只能用于POST请求。在 HttpClient程序包中有两个类可以完成此项工作,它们分别是UrlEncodedFormEntity类与MultipartEntity类。这两个类均实现了HttpEntity接口。
(1)
使用最多的是UrlEncodedFormEntity类。通过该类创建的对象可以模拟传统的HTML表单传送POST请求中的参数。如下面的表单:
 
<form action="http://localhost/index.html" method="POST">
    <input type="text" name="param1" value="中国"/>
    <input type="text" name="param2" value="value2"/>
    <inupt type="submit" value="submit"/>
</form>
 
我们可以用下面的代码实现:
 
List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("param1", "中国"));
formParams.add(new BasicNameValuePair("param2", "value2"));
HttpEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
 
HttpPost request = new HttpPost(“http://localhost/index.html”);
request.setEntity(entity);
 
当然,如果想查看HTTP数据格式,可以通过HttpEntity对象的各种方法取得。如:
 
List formParams = new ArrayList();
formParams.add(new BasicNameValuePair("param1", "中国"));
formParams.add(new BasicNameValuePair("param2", "value2"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
 
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(entity));
System.out.println(EntityUtils.toString(entity));
 
上例的打印结果如下:
 
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    39
    UTF-8
    param1=%E4%B8%AD%E5%9B%BD&param2=value2 
 
(2)
除了传统的application/x-www-form-urlencoded表单,我们另一个经常用到的是上传文件用的表单,这种表单的类型为 multipart/form-data。在HttpClient程序扩展包(HttpMime)中专门有一个类与之对应,那就是 MultipartEntity类。此类同样实现了HttpEntity接口。如下面的表单:
 
<form action="http://localhost/index.html" method="POST"
        enctype="multipart/form-data">
    <input type="text" name="param1" value="中国"/>
    <input type="text" name="param2" value="value2"/>
    <input type="file" name="param3"/>
    <inupt type="submit" value="submit"/>
</form>
 
我们可以用下面的代码实现:
 
MultipartEntity entity = new MultipartEntity();
entity.addPart("param1", new StringBody("中国", Charset.forName("UTF-8")));
entity.addPart("param2", new StringBody("value2", Charset.forName("UTF-8")));
entity.addPart("param3", new FileBody(new File("C:\\1.txt")));
 
HttpPost request = new HttpPost(“http://localhost/index.html”);
request.setEntity(entity);
 
HTTP响应
 
HttpClient程序包对于HTTP响应的处理较之HTTP请求来说是简单多了,其过程同样使用了HttpEntity接口。我们可以从 HttpEntity对象中取出数据流(InputStream),该数据流就是服务器返回的响应数据。需要注意的是,HttpClient程序包不负责解析数据流中的内容。如:
 
HttpUriRequest request = ...;
HttpResponse response = httpClient.execute(request);
 
// 从response中取出HttpEntity对象
HttpEntity entity = response.getEntity();
 
// 查看entity的各种指标
System.out.println(entity.getContentType());
System.out.println(entity.getContentLength());
System.out.println(EntityUtils.getContentCharSet(entity));
 
// 取出服务器返回的数据流
InputStream stream = entity.getContent();
 
// 以任意方式操作数据流stream
// 调用方式 略
 
附注:
 
本文说明的是HttpClient 4.0.1,该程序包(包括依赖的程序包)由以下几个JAR包组成:
 
commons-logging-1.1.1.jar
commons-codec-1.4.jar
httpcore-4.0.1.jar
httpclient-4.0.1.jar
apache-mime4j-0.6.jar
httpmime-4.0.1.jar
 
可以在此处下载完整的JAR包。
 
 
 
 
现在Apache已经发布了:HttpCore 4.0-beta3、HttpClient 4.0-beta1。
到此处可以去下载这些源代码:http://hc.apache.org/downloads.cgi
另外,还需要apache-mime4j-0.5.jar 包。
 
在这里先写个简单的POST方法,中文资料不多,英文不太好。
package test;
 
import java.util.ArrayList;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
 
public class Test2 {
    public static void main(String[] args) throws Exception {
        DefaultHttpClient httpclient = new DefaultHttpClient();      //实例化一个HttpClient
        HttpResponse response = null;
        HttpEntity entity = null;
        httpclient.getParams().setParameter(
                ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);  //设置cookie的兼容性
        HttpPost httpost = new HttpPost("http://127.0.0.1:8080/pub/jsp/getInfo");           //引号中的参数是:servlet的地址
        List <NameValuePair> nvps = new ArrayList <NameValuePair>();                     
        nvps.add(new BasicNameValuePair("jqm", "fb1f7cbdaf2bf0a9cb5d43736492640e0c4c0cd0232da9de"));  
        //   BasicNameValuePair("name", "value"), name是post方法里的属性, value是传入的参数值
        nvps.add(new BasicNameValuePair("sqm", "1bb5b5b45915c8"));
        httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));            //将参数传入post方法中
        response = httpclient.execute(httpost);                                               //执行
        entity = response.getEntity();                                                             //返回服务器响应
        try{
            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());                           //服务器返回状态
            Header[] headers = response.getAllHeaders();                    //返回的HTTP头信息
            for (int i=0; i<headers.length; i++) {                              
            System.out.println(headers[i]);
            }
            System.out.println("----------------------------------------");
            String responseString = null;
            if (response.getEntity() != null) {
            responseString = EntityUtils.toString(response.getEntity());      / /返回服务器响应的HTML代码
            System.out.println(responseString);                                   //打印出服务器响应的HTML代码
            }
        } finally {
            if (entity != null)                          
            entity.consumeContent();                                                   // release connection gracefully
        }
        System.out.println("Login form get: " + response.getStatusLine());
        if (entity != null) {
        entity.consumeContent();
        }
       
    }
}
 
 
 
 
HttpClient4.0 学习实例 - 页面获取
 
HttpClient 4.0出来不久,所以网络上面相关的实例教程不多,搜httpclient得到的大部分都是基于原 Commons HttpClient 3.1 (legacy) 包的,官网下载页面:http://hc.apache.org/downloads.cgi,如果大家看了官网说明就明白httpclient4.0是从原包分支出来独立成包的,以后原来那个包中的httpclient不会再升级,所以以后我们是用httpclient新分支,由于4.0与之前的3.1包结构以及接口等都有较大变化,所以网上搜到的实例大部分都是不适合4.0的,当然,我们可以通过那些实例去琢磨4.0的用法,我也是新手,记录下学习过程方便以后检索
 
本实例我们来获取抓取网页编码,内容等信息
 
默认情况下,服务器端会根据客户端的请求头信息来返回服务器支持的编码,像google.cn他本身支持utf-8,gb2312等编码,所以如果你在头部中不指定任何头部信息的话他默认会返回gb2312编码,而如果我们在浏览器中直接访问google.cn,通过httplook,或者firefox 的firebug插件查看返回头部信息的话会发现他返回的是UTF-8编码
 
下面我们还是看实例来解说吧,注释等我也放代码里面解释,放完整代码,方便新手理解
 
本实例将
 
使用的httpclient相关包
httpclient-4.0.jar
httpcore-4.0.1.jar
httpmime-4.0.jar
commons-logging-1.0.4.jar等其它相关包
 
// HttpClientTest.java
package com.baihuo.crawler.test;
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
 
class HttpClientTest {
 
    public final static void main(String[] args) throws Exception {
 
        // 初始化,此处构造函数就与3.1中不同
        HttpClient httpclient = new DefaultHttpClient();
 
        HttpHost targetHost = new HttpHost("www.google.cn");
        //HttpGet httpget = new HttpGet("http://www.apache.org/");
        HttpGet httpget = new HttpGet("/");
 
        // 查看默认request头部信息
        System.out.println("Accept-Charset:" + httpget.getFirstHeader("Accept-Charset"));
        // 以下这条如果不加会发现无论你设置Accept-Charset为gbk还是utf-8,他都会默认返回gb2312(本例针对google.cn来说)
        httpget.setHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.2)");
        // 用逗号分隔显示可以同时接受多种编码
        httpget.setHeader("Accept-Language", "zh-cn,zh;q=0.5");
        httpget.setHeader("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
        // 验证头部信息设置生效
        System.out.println("Accept-Charset:" + httpget.getFirstHeader("Accept-Charset").getValue());
 
        // Execute HTTP request
        System.out.println("executing request " + httpget.getURI());
        HttpResponse response = httpclient.execute(targetHost, httpget);
        //HttpResponse response = httpclient.execute(httpget);
 
        System.out.println("----------------------------------------");
        System.out.println("Location: " + response.getLastHeader("Location"));
        System.out.println(response.getStatusLine().getStatusCode());
        System.out.println(response.getLastHeader("Content-Type"));
        System.out.println(response.getLastHeader("Content-Length"));
        
        System.out.println("----------------------------------------");
 
        // 判断页面返回状态判断是否进行转向抓取新链接
        int statusCode = response.getStatusLine().getStatusCode();
        if ((statusCode == HttpStatus.SC_MOVED_PERMANENTLY) ||
                (statusCode == HttpStatus.SC_MOVED_TEMPORARILY) ||
                (statusCode == HttpStatus.SC_SEE_OTHER) ||
                (statusCode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
            // 此处重定向处理  此处还未验证
            String newUri = response.getLastHeader("Location").getValue();
            httpclient = new DefaultHttpClient();
            httpget = new HttpGet(newUri);
            response = httpclient.execute(httpget);
        }
 
        // Get hold of the response entity
        HttpEntity entity = response.getEntity();
        
        // 查看所有返回头部信息
        Header headers[] = response.getAllHeaders();
        int ii = 0;
        while (ii < headers.length) {
            System.out.println(headers[ii].getName() + ": " + headers[ii].getValue());
            ++ii;
        }
        
        // If the response does not enclose an entity, there is no need
        // to bother about connection release
        if (entity != null) {
            // 将源码流保存在一个byte数组当中,因为可能需要两次用到该流,
            byte[] bytes = EntityUtils.toByteArray(entity);
            String charSet = "";
            
            // 如果头部Content-Type中包含了编码信息,那么我们可以直接在此处获取
            charSet = EntityUtils.getContentCharSet(entity);
 
            System.out.println("In header: " + charSet);
            // 如果头部中没有,那么我们需要 查看页面源码,这个方法虽然不能说完全正确,因为有些粗糙的网页编码者没有在页面中写头部编码信息
            if (charSet == "") {
                regEx="(?=<meta).*?(?<=charset=[\\'|\\\"]?)([[a-z]|[A-Z]|[0-9]|-]*)";
                p=Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
                m=p.matcher(new String(bytes));  // 默认编码转成字符串,因为我们的匹配中无中文,所以串中可能的乱码对我们没有影响
                result=m.find();
                if (m.groupCount() == 1) {
                    charSet = m.group(1);
                } else {
                    charSet = "";
                }
            }
            System.out.println("Last get: " + charSet);
            // 至此,我们可以将原byte数组按照正常编码专成字符串输出(如果找到了编码的话)
            System.out.println("Encoding string is: " + new String(bytes, charSet));
        }
 
        httpclient.getConnectionManager().shutdown();        
    }
 
}



http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113252.html
posted @ 2012-09-26 16:46 abin 阅读(5391) | 评论 (1)编辑 收藏

第六章 高级主题

6.1 自定义客户端连接

在特定条件下,也许需要来定制HTTP报文通过线路传递,越过了可能使用的HTTP参数来处理非标准不兼容行为的方式。比如,对于Web爬虫,它可能需要强制HttpClient接受格式错误的响应头部信息,来抢救报文的内容。

通常插入一个自定义的报文解析器的过程或定制连接实现需要几个步骤:

提供一个自定义LineParser/LineFormatter接口实现。如果需要,实现报文解析/格式化逻辑。

class MyLineParser extends BasicLineParser {
@Override
public Header parseHeader(
final CharArrayBuffer buffer) throws ParseException {
try {
return super.parseHeader(buffer);
} catch (ParseException ex) {
// 压制ParseException异常
return new BasicHeader("invalid", buffer.toString());
}
}
}

提过一个自定义的OperatedClientConnection实现。替换需要自定义的默认请求/响应解析器,请求/响应格式化器。如果需要,实现不同的报文写入/读取代码。

class MyClientConnection extends DefaultClientConnection {
@Override
protected HttpMessageParser createResponseParser(
final SessionInputBuffer buffer,
final HttpResponseFactory responseFactory,
final HttpParams params) {
return new DefaultResponseParser(buffer,
new MyLineParser(),responseFactory,params);
}
}

为了创建新类的连接,提供一个自定义的ClientConnectionOperator接口实现。如果需要,实现不同的套接字初始化代码。

class MyClientConnectionOperator extends
DefaultClientConnectionOperator {
public MyClientConnectionOperator(
final SchemeRegistry sr) {
super(sr);
}
@Override
public OperatedClientConnection createConnection() {
return new MyClientConnection();
}
}

为了创建新类的连接操作,提供自定义的ClientConnectionManager接口实现。

class MyClientConnManager extends SingleClientConnManager {
public MyClientConnManager(
final HttpParams params,
final SchemeRegistry sr) {
super(params, sr);
}
@Override
protected ClientConnectionOperator createConnectionOperator(
final SchemeRegistry sr) {
return new MyClientConnectionOperator(sr);
}
}

6.2 有状态的HTTP连接

HTTP规范假设session状态信息通常是以HTTP cookie格式嵌入在HTTP报文中的,因此HTTP连接通常是无状态的,这个假设在现实生活中通常是不对的。也有一些情况,当HTTP连接使用特定的用户标识或特定的安全上下文来创建时,因此不能和其它用户共享,只能由该用户重用。这样的有状态的HTTP连接的示例就是NTLM认证连接和使用客户端证书认证的SSL连接。

6.2.1 用户令牌处理器

HttpClient依赖UserTokenHandler接口来决定给定的执行上下文是否是用户指定的。如果这个上下文是用户指定的或者如果上下文没有包含任何资源或关于当前用户指定详情而是null,令牌对象由这个处理器返回,期望唯一地标识当前的用户。用户令牌将被用来保证用户指定资源不会和其它用户来共享或重用。

如果它可以从给定的执行上下文中来获得,UserTokenHandler接口的默认实现是使用主类的一个实例来代表HTTP连接的状态对象。UserTokenHandler将会使用基于如NTLM或开启的客户端认证SSL会话认证模式的用户的主连接。如果二者都不可用,那么就不会返回令牌。

如果默认的不能满足它们的需要,用户可以提供一个自定义的实现:
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.setUserTokenHandler(new UserTokenHandler() {
public Object getUserToken(HttpContext context) {
return context.getAttribute("my-token");
}
});

6.2.2 用户令牌和执行上下文

在HTTP请求执行的过程中,HttpClient添加了下列和用户标识相关的对象到执行上下文中:

'http.user-token':对象实例代表真实的用户标识,通常期望Principle接口的实例。

我们可以在请求被执行后,通过检查本地HTTP上下文的内容,发现是否用于执行请求的连接是有状态的。
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
Object userToken = localContext.getAttribute(ClientContext.USER_TOKEN);
System.out.println(userToken);
6.2.2.1 持久化有状态的连接
请注意带有状态对象的持久化连接仅当请求被执行时,相同状态对象被绑定到执行上下文时可以被重用。所以,保证相同上下文重用于执行随后的相同用户,或用户令牌绑定到之前请求执行上下文的HTTP请求是很重要的。
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext1 = new BasicHttpContext();
HttpGet httpget1 = new HttpGet("http://localhost:8080/");
HttpResponse response1 = httpclient.execute(httpget1, localContext1);
HttpEntity entity1 = response1.getEntity();
if (entity1 != null) {
entity1.consumeContent();
}
Principal principal = (Principal) localContext1.getAttribute(
ClientContext.USER_TOKEN);
HttpContext localContext2 = new BasicHttpContext();
localContext2.setAttribute(ClientContext.USER_TOKEN, principal);
HttpGet httpget2 = new HttpGet("http://localhost:8080/");
HttpResponse response2 = httpclient.execute(httpget2, localContext2);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null) {
entity2.consumeContent();
}

转载自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113251.html
posted @ 2012-09-26 16:45 abin 阅读(796) | 评论 (0)编辑 收藏

第四章 HTTP认证
HttpClient提供对由HTTP标准规范定义的认证模式的完全支持。HttpClient的认证框架可以扩展支持非标准的认证模式,比如NTLM和SPNEGO。

4.1 用户凭证

任何用户身份验证的过程都需要一组可以用于建立用户身份的凭据。用户凭证的最简单的形式可以仅仅是用户名/密码对。UsernamePasswordCredentials代表了一组包含安全规则和明文密码的凭据。这个实现对由HTTP标准规范中定义的标准认证模式是足够的

UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

输出内容为:

user
pwd

NTCredentials是微软Windows指定的实现,它包含了除了用户名/密码对外,一组额外的Windows指定的属性,比如用户域名的名字,比如在微软的Windows网络中,相同的用户使用不同设置的认证可以属于不同的域。

NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

输出内容为:

DOMAIN/user
pwd

4.2 认证模式

AuthScheme接口代表了抽象的,面向挑战-响应的认证模式。一个认证模式期望支持如下的功能:
  • 解析和处理由目标服务器在对受保护资源请求的响应中发回的挑战。
  • 提供处理挑战的属性:认证模式类型和它的参数,如果可用,比如这个认证模型可应用的领域。
  • 对给定的凭证组和HTTP请求对响应真实认证挑战生成认证字符串。
要注意认证模式可能是有状态的,涉及一系列的挑战-响应交流。HttpClient附带了一些AuthScheme实现:
  • Basic(基本):Basic认证模式定义在RFC 2617中。这个认证模式是不安全的,因为凭据以明文形式传送。尽管它不安全,如果用在和TLS/SSL加密的组合中,Basic认证模式是完全够用的。
  • Digest(摘要):Digest认证模式定义在RFC 2617中。Digest认证模式比Basic有显著的安全提升,对不想通过TLS/SL加密在完全运输安全上开销的应用程序来说也是很好的选择。
  • NTLM:NTLM是一个由微软开发的优化Windows平台的专有认证模式。NTLM被认为是比Digest更安全的模式。这个模式需要外部的NTLM引擎来工作。要获取更多详情请参考包含在HttpClient发布包中的NTLM_SUPPORT.txt文档。

4.3 HTTP认证参数

有一些可以用于定制HTTP认证过程和独立认证模式行为的参数:
  • 'http.protocol.handle-authentication':定义了是否认证应该被自动处理。这个参数期望的得到一个java.lang.Boolean类型的值。如果这个参数没有被设置,HttpClient将会自动处理认证。
  • 'http.auth.credential-charset':定义了当编码用户凭证时使用的字符集。这个参数期望得到一个java.lang.String类型的值。如果这个参数没有被设置,那么就会使用US-ASCII。

4.4 认证模式注册表

HttpClient使用AuthSchemeRegistry类维护一个可用的认证模式的注册表。对于每个默认的下面的模式是注册过的:
  • Basic:基本认证模式
  • Digest:摘要认证模式
请注意NTLM模式没有对每个默认的进行注册。NTLM不能对每个默认开启是应为许可和法律上的原因。要获取更详细的关于如何开启NTLM支持的内容请看这部分。

4.5 凭据提供器

凭据提供器意来维护一组用户凭据,还有能够对特定认证范围生产用户凭据。认证范围包括主机名,端口号,领域名称和认证模式名称。当使用凭据提供器来注册凭据时,我们可以提供一个通配符(任意主机,任意端口,任意领域,任意模式)来替代确定的属性值。如果直接匹配没有发现,凭据提供器期望被用来发现最匹配的特定范围。

HttpClient可以和任意实现了CredentialsProvider接口的凭据提供器的物理代表一同工作。默认的CredentialsProvider实现被称为BasicCredentialsProvider,它是简单的凭借java.util.HashMap的实现。
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("somehost", AuthScope.ANY_PORT),
new UsernamePasswordCredentials("u1", "p1"));
credsProvider.setCredentials(
new AuthScope("somehost", 8080),
new UsernamePasswordCredentials("u2", "p2"));
credsProvider.setCredentials(
new AuthScope("otherhost", 8080, AuthScope.ANY_REALM, "ntlm"),
new UsernamePasswordCredentials("u3", "p3"));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 80, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("somehost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
new AuthScope("otherhost", 8080, null, "ntlm")));

输出内容为:

[principal: u1]
[principal: u2]
null
[principal: u3]

4.6 HTTP认证和执行上下文

HttpClient依赖于AuthState类来跟踪关于认证过程状态的详细信息。在HTTP请求执行过程中,HttpClient创建2个AuthState的实例:一个对于目标主机认证,另外一个对于代理认证。如果目标服务器或代理需要用户认证,那么各自的AuthState实例将会被在认证处理过程中使用的AuthScope,AuthScheme和Crednetials来填充。AuthState可以被检查来找出请求的认证是什么类型的,是否匹配AuthScheme的实现,是否凭据提供器对给定的认证范围去找用户凭据。

在HTTP请求执行的过程中,HttpClient添加了下列和认证相关的对象到执行上下文中:

  • 'http.authscheme-registry':AuthSchemeRegistry实例代表真实的认证模式注册表。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.credentials-provider':CookieSpec实例代表了真实的凭据提供器。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.target-scope':AuthState实例代表了真实的目标认证状态。在本地内容中设置的这个属性的值优先于默认的。
  • 'http.auth.proxy-scope':AuthState实例代表了真实的代理认证状态。在本地内容中设置的这个属性的值优先于默认的。

本地的HttpContext对象可以用于定制HTTP认证内容,并先于请求执行或在请求被执行之后检查它的状态:

HttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpget = new HttpGet("http://localhost:8080/");
HttpResponse response = httpclient.execute(httpget, localContext);
AuthState proxyAuthState = (AuthState) localContext.getAttribute(
ClientContext.PROXY_AUTH_STATE);
System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = (AuthState) localContext.getAttribute(
ClientContext.TARGET_AUTH_STATE);
System.out.println("Target auth scope: " + targetAuthState.getAuthScope());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());

4.7 抢占认证

HttpClient不支持开箱的抢占认证,因为滥用或重用不正确的抢占认证可能会导致严重的安全问题,比如将用户凭据以明文形式发送给未认证的第三方。因此,用户期望评估抢占认证和在它们只能应用程序环境内容安全风险潜在的好处,而且要求使用如协议拦截器的标准HttpClient扩展机制添加对抢占认证的支持。

这是一个简单的协议拦截器,如果没有企图认证,来抢先引入BasicScheme的实例到执行上下文中。请注意拦截器必须在标准认证拦截器之前加入到协议处理链中。

HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
public void process(final HttpRequest request,
final HttpContext context) throws HttpException, IOException {
AuthState authState = (AuthState) context.getAttribute(
ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
// 如果没有初始化auth模式
if (authState.getAuthScheme() == null) {
AuthScope authScope = new AuthScope(
targetHost.getHostName(),
targetHost.getPort());
// 获得匹配目标主机的凭据
Credentials creds = credsProvider.getCredentials(authScope);
// 如果发现了,抢先生成BasicScheme
if (creds != null) {
authState.setAuthScheme(new BasicScheme());
authState.setCredentials(creds);
}
}
}
};
DefaultHttpClient httpclient = new DefaultHttpClient();
// 作为第一个拦截器加入到协议链中
httpclient.addRequestInterceptor(preemptiveAuth, 0);

4.8 NTLM 认证

当前HttpClient没有提对开箱的NTLM认证模式的支持也可能永远也不会。这个原因是法律上的而不是技术上的。然而,NTLM认证可以使用外部的NTLM引擎比如JCIFS[http://jcifs.samba.org/]来开启,类库由Samba[http://www.samba.org/]项目开发,作为它们Windows的交互操作程序套装的一部分。要获取详细内容请参考HttpClient发行包中包含的NTLM_SUPPORT.txt文档。

4.8.1 NTLM连接持久化

NTLM认证模式是在计算开销方面昂贵的多的,而且对标准的Basic和Digest模式的性能影响也很大。这很可能是为什么微软选择NTLM认证模式为有状态的主要原因之一。也就是说,一旦认证通过,用户标识是和连接的整个生命周期相关联的。NTLM连接的状态特性使得连接持久化非常复杂,对于明显的原因,持久化NTLM连接不能被使用不同用户标识的用户重用。标准的连接管理器附带HttpClient是完全能够管理状态连接的。而逻辑相关的,使用同一session和执行上下文为了让它们了解到当前的用户标识的请求也是极为重要的。否则,HttpClient将会终止对每个基于NTLM保护资源的HTTP请求创建新的HTTP连接。要获取关于有状态的HTTP连接的详细讨论,请参考这个部分。

因为NTLM连接是有状态的,通常建议使用相对简单的方法触发NTLM认证,比如GET或HEAD,而重用相同的连接来执行代价更大的方法,特别是它们包含请求实体,比如POST或PUT。

DefaultHttpClient httpclient = new DefaultHttpClient();
NTCredentials creds = new NTCredentials("user", "pwd", "myworkstation", "microsoft.com");
httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
HttpHost target = new HttpHost("www.microsoft.com", 80, "http");
// 保证相同的内容来用于执行逻辑相关的请求
HttpContext localContext = new BasicHttpContext();
// 首先执行简便的方法。这会触发NTLM认证
HttpGet httpget = new HttpGet("/ntlm-protected/info");
HttpResponse response1 = httpclient.execute(target, httpget, localContext);
HttpEntity entity1 = response1.getEntity();
if (entity1 != null) {
entity1.consumeContent();
}
//之后使用相同的内容(和连接)执行开销大的方法。
HttpPost httppost = new HttpPost("/ntlm-protected/form");
httppost.setEntity(new StringEntity("lots and lots of data"));
HttpResponse response2 = httpclient.execute(target, httppost, localContext);
HttpEntity entity2 = response2.getEntity();
if (entity2 != null) {
entity2.consumeContent();
}

 



转载自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113247.html
posted @ 2012-09-26 16:44 abin 阅读(827) | 评论 (0)编辑 收藏

仅列出标题
共50页: First 上一页 25 26 27 28 29 30 31 32 33 下一页 Last