使用HttpConnection发送Post请求

这是在项目中运用HttpURLConnection发送post请求(我们项目中是用来发送soap),完整的处理,包括如何处理异常。需要注意一个小地方,我们把创建URL放在afterPropertiesSet方法中,是因为这个类只是为下游某一个特定的Service服务的,如果要作用共用的,不能这样做。
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;

public class HttpClient implements InitializingBean
{
	private static final String DEBUG_HTTP_RESULT = "Result of calling http service: ";
	private static final String ERROR_DEFAULT_HTTP = "Failed to call HTTP Service at ";
	private static final String ERROR_CONNECTION = "Failed to connect to ";
	private static final String ERROR_TIMEOUT = "Timeout occured connecting to ";
	private static final String ERROR_UNKNOWN_RESPONSE_CODE_RECIEVED = "Unknown Response Code %s recieved: ";
	private static final String ERROR_INTERNAL_ERROR = "Internal Server Error: ";
	private static final String ERROR_BAD_REQUEST = "Bad Request: ";

	private static final String URL_FORMAT = "%s://%s:%s";

	private static final String REQUEST_METHOD_POST = "POST";

	private static final Logger LOGGER = Logger.getLogger(HttpClient.class);

	private String m_hostname = "";
	private String m_protocol = "";
	private String m_port = "";
	
	//default is set to 10 seconds
	private int m_timeoutMs = 10000;
	
	private URL endpoint = null;

	/**
	 * Must be called after connection params are set
	 * @throws MalformedURLException
	 */
	public void afterPropertiesSet() throws MalformedURLException
	{
		endpoint = new URL(getHttpEndpoint());
	}

	public byte[] send(byte[] input, int numRetries) throws DataTransportException
	{
		byte[] payload = null;
		
		for (int i=1; i<=numRetries; i++)
		{
			try
			{
				//create a new connection for each request
				HttpURLConnection connection = (HttpURLConnection) endpoint.openConnection();
				connection.setReadTimeout(m_timeoutMs);
				connection.setConnectTimeout(m_timeoutMs);
				connection.setRequestMethod(REQUEST_METHOD_POST);
				connection.setDoInput(true);
				connection.setDoOutput(true);
	
				//write our request to the post body using an outputstream
				DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
				wr.write(input);
				wr.flush();
				wr.close();
		      
				//check for success or failure
				handleResponseCodes(connection);
	
				//how big is our response
				int length = connection.getContentLength();
				LOGGER.debug("bytes received: " + length);
	
				//read response
				payload = readPayload(connection, length);
				break;
			}
			catch (ConnectException ce)
			{
			  hrowDataTransportException(..........)			
			}
			catch (SocketTimeoutException ste)
			{
				throwDataTransportException(.....);
			}
			catch (Throwable t)
			{
				throwDataTransportException(i, numRetries, EventLogIds.HTTP_DEFAULT_ERROR,
						ERROR_DEFAULT_HTTP + endpoint, t);
			}
		}
		return payload;
	}
	
	/**
	 * Logs error message and throws exception
	 * @param errorCode
	 * @param errorMessage
	 * @param e
	 * @throws CommonHotelException
	 */
	private void throwDataTransportException(int currentAttempt, int totalAttempt, int errorCode, 
											String errorMessage, Throwable e)
			throws DataTransportException
	{
		if (currentAttempt==totalAttempt)
		{
			throw new DataTransportException(errorMessage, errorCode, e);
		}
		else
		{
			String message = String.format("Http Client attempt %d of %d failed: %s", 
					currentAttempt, totalAttempt, errorMessage);
			EventLogEntry.logEvent(LOGGER, Level.WARN, errorCode, message, e);
		}
	}

	/**
	 * Checks http error code and message
	 * @param errorCode
	 * @param errorMessage
	 * @param e
	 * @throws IOException 
	 * @throws CommonHotelException
	 */
	private void throwDataTransportException(int errorCode, String errorMessage, Throwable e, InputStream errorStream)
			throws DataTransportException, IOException
	{
		//try to read from stderr
		StringBuilder builder = new StringBuilder(errorMessage);
		builder.append(".  Details: ");
		if(errorStream != null)
		{
			BufferedReader in = null;
			try
			{
				in = new BufferedReader(new InputStreamReader(errorStream));
				String line = in.readLine();
				while(line != null)
				{
					builder.append(line);
					line = in.readLine();
				}
			}
			catch (IOException e1)
			{
				LOGGER.warn(Utilities.getExceptionStackTrace(e1));
			}
			finally
			{
				if(in != null)
				{
					in.close();
				}
			}
			
		}
		throw new DataTransportException(builder.toString(), errorCode, e);
	}

	private void handleResponseCodes(HttpURLConnection connection)
			throws DataTransportException, IOException
	{
		int responseCode = connection.getResponseCode();
		String responseMessage = connection.getResponseMessage();
		InputStream errorStream = connection.getErrorStream();

		switch (responseCode)
		{
		case HttpURLConnection.HTTP_OK:
			EventLogEntry.logEvent(LOGGER, Level.DEBUG,
					EventLogIds.HTTP_TRANSFER_SUCCESS, DEBUG_HTTP_RESULT
							+ responseMessage);
			break;
		case HttpURLConnection.HTTP_BAD_REQUEST:
			throwDataTransportException(EventLogIds.HTTP_BAD_REQUEST, ERROR_BAD_REQUEST
					+ responseMessage, null, errorStream);
		case HttpURLConnection.HTTP_INTERNAL_ERROR:
			throwDataTransportException(EventLogIds.HTTP_INTERNAL_SERVER_ERROR,
					ERROR_INTERNAL_ERROR + responseMessage, null, errorStream);
		default:
			String message = String.format(ERROR_UNKNOWN_RESPONSE_CODE_RECIEVED, responseCode);
			throwDataTransportException(EventLogIds.HTTP_DEFAULT_ERROR,
					message + responseMessage, null, errorStream);
		}
	}

	
	/**
	 * reads all bytes in the response
	 * 
	 * @param connection
	 * @param length
	 *            must specify length of expected payload
	 * @throws IOException
	 */
	private byte[] readPayload(HttpURLConnection connection, int length) throws IOException
	{
		byte[] payload = new byte[length];
		//read all bytes
		//TODO: need a way to break loop in error cases
		
		InputStream is = null;
		try{
			is = connection.getInputStream();
			int bytesRemaining = length;
			while( bytesRemaining > 0)
			{
				int off = length - bytesRemaining;
				int avail = is.available();
				int bytesRead = is.read(payload, off, avail);
				bytesRemaining -= bytesRead;
			}
		}
		finally{
			if(is != null)
			{
				is.close();
			}
		}
		return payload;
	}

	private String getHttpEndpoint()
	{
		return String.format(URL_FORMAT, m_protocol, m_hostname, m_port);
	}
	
	/**
	 * Set hostname we are sending to
	 * @param hostname
	 */
	public void setHostname(String hostname)
	{
		m_hostname = hostname;
	}

	/**
	 * Set protocol.  eg. "http"
	 * @param protocol
	 */
	public void setProtocol(String protocol)
	{
		m_protocol = protocol;
	}

	/**
	 * Set port
	 * @param port
	 */
	public void setPort(String port)
	{
		m_port = port;
	}

	public void setTimeoutMs(int timeoutMs)
	{
		m_timeoutMs = timeoutMs;
	}

}

猜你喜欢

转载自cyril0513.iteye.com/blog/1764728