728x90

개요

Apache Http Client를 통해 웹페이지에서 파일업로드를 하듯이 파일전송도 할 수 있습니다. 간단한 전송 예제코드를 보이고, 주의점을 설명합니다.

(방법이 어렵진 않으나 모르면 발생하는 오류를 해결하기 어려워 이 문서를 작성합니다.)

예제코드

	public void upload(
			final Map<String,Object> paramMap,
			final Properties prop) {
		HttpEntity multipartEntity = null;
		try {
			// <패스|쿼리|바디 필수값 검증>
			final String filePath = (String) paramMap.get("filePath");
			if (StringUtils.isBlank(filePath)) {
				throw new IllegalArgumentException("필수값 누락 : filePath");
			}
			final File file = new File(filePath);
			if (!file.exists()) {
				throw new IllegalArgumentException("필수파일 누락. file.getAbsolutePath():" + file.getAbsolutePath());
			}
			// </패스|쿼리|바디 필수값 검증>
			if (log.isDebugEnabled()) {
				log.debug("File.separator:" + File.separator);
			}
			String fileName = (String) paramMap.get("fileName");
			if (StringUtils.isBlank(fileName)) {
				fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
			}

			final String url = prop.getProperty("URL");

			multipartEntity = MultipartEntityBuilder.create()
					.addBinaryBody("file", file, ContentType.MULTIPART_FORM_DATA, fileName).build();

			// <http-method="POST">
			final HttpUriRequest httpReq = new HttpPost(url);
			// </http-method="POST">
//			httpReq.setHeader("Content-Type","multipart/form-data");	// !주의! 'Content-Type'을 직접 지정하지 말고, MultipartEntityBuilder에서 자동으로 생성되는 대로 사용할 것.
			httpReq.setHeader("Accept","*/*");
			httpReq.setHeader("Accept-Encoding","gzip, deflate, br");

			// <http-method="POST" "multipart/form-data">
			((HttpEntityEnclosingRequestBase) httpReq).setEntity(multipartEntity);
			// </http-method="POST" "multipart/form-data">

			int timeoutSecond = 8;
			RequestConfig config = RequestConfig.custom()
					.setConnectTimeout(timeoutSecond * 1000)
					.setConnectionRequestTimeout(timeoutSecond * 1000)
					.setSocketTimeout(timeoutSecond * 1000).build();
			CloseableHttpClient httpclient = HttpClientBuilder.create()
					.setDefaultRequestConfig(config).build();
			httpclient.execute(httpReq);
		} catch (final Throwable t) {
			final String message = "API 파일업로드 실패.";
			throw new RuntimeException(message + " iParam:" + paramMap + ", prop:" + prop, t);
		}
	}

중요한 코드 위주로 간략화시키려하다보니 프로젝트 코드와 차이가 있는 편입니다. 핵심 내용만 참고하고, 응용할 필요가 있습니다.

해설

전송 방식은 POST, 파일데이터는 ‘MultipartEntityBuilder’를 이용해 추가합니다. 헤더에는 “Content-Type”을 직접 입력하지 않도록 주의합니다.(이유는 아래 [주의점]에서 후술.)

그 외에는 일반적인 POST와 동일합니다.

주의점

MultipartEntityBuilder를 사용할 때, 아래와 같이 직접 헤더에 "multipart/form-data"로 입력하면 안 됩니다.

httpReq.setHeader("Content-Type","multipart/form-data");

위와 같이 코딩했다면, 응답으로 '400 Bad Request'를 받게 될 것입니다.

왜냐하면 파일 데이터 전송 시 boundary도 필요하기 때문입니다. boundary는 파일데이터와 다른 데이터를 구분하는 경계로 사용하며, 이 boundary가 아래처럼 Content-Type에 함께 있어야 합니다.

Content-Type : multipart/form-data; boundary=(자동생성)

다만, MultipartEntityBuilder를 사용하여 Entity를 입력하면 이러한 헤더를 자동으로 입력해주므로 boundary를 어떻게 입력할 것인지 고민하지 않아도 됩니다.

참고자료

 

<끝> [DEV240827a]

반응형

+ Recent posts