Ниже приведен фрагмент для загрузки inputStream HttpServletRequest в S3 и последующей его загрузки.
public void init() {
s3Client = AmazonS3ClientBuilder.defaultClient();
//create bucket if not exists
}
@PostMapping( Consumes - Multipart/form-data)
public String send(HttpServletRequest request) {
//validate request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if(!isMultipart) // reject
if (Long.parseLong(request.getHeader("Content-length")) > maxLength) // reject
//Put request in S3
ObjectMetaData objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(Long.parseLong(request.getHeader("Content-length")));
objectMetadata.setContentType(request.getHeader("Content-type"));
s3Client.putObject(bucket, key, request.getInputStream, objectMetadata);
CustomServletRequestContext ctx = new CustomServletRequestContext(is, request.getCharacterEncoding(), request.getContentLength(), request.getContentType());
}
public void download(CustomServletRequestContext ctx) {
// Get data from S3
GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);
S3Object s3Object = s3Client.getObject(getObjectRequest);
InputStream is = s3Object.getObjectContent();
ServletFileUpload upload = new ServletFileUpload();
upload.setSizeMax(maxLength);
FileItemIterator iterator = upload.getItemIterator(ctx); // need context object
while (iterator.hasNext()) {
FileItemStream item = iterator.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
process IOUtils.toString(stream, "UTF-8") // throws randomly Premature end of Stream exception
} else {
process Streams.asString(stream);
}
}
}
CustomServletRequestContext - необходимо создать его для apache-commons-fileupload api, чтобы получить итератор частей во время чтения, для которого требуется контекст, как написановыше.
class CustomServletRequestContext implements UploadContext {
private final InputStream is;
private final String characterEncoding;
private final int contentLength;
private final String contentType;
public MyServletRequestContext(InputStream is, String characterEncoding, int contentLength, String contentType) {
this.is = is;
this.characterEncoding = characterEncoding;
this.contentLength = contentLength;
this.contentType = contentType;
}
public String getCharacterEncoding() {
return characterEncoding;
}
public String getContentType() {
return contentType;
}
public int getContentLength() {
return contentLength;
}
public long contentLength() {
return contentLength;
}
public InputStream getInputStream() throws IOException {
return is;
}
public String toString() {
return String.format("ContentLength=%s, ContentType=%s", this.contentLength(), this.getContentType());
}
}
Обнаружено, что не удается открыть HttpServletRequest inputStream для любого вида проверки, которая требует чтения inputStream перед помещением в S3.В противном случае это приведет к несоответствию длины содержимого позже, так как размеры не будут совпадать, так как inputStream уже был прочитан, а смещение увеличено с 0.
Так как можно выполнить проверку типа содержимого каждой части перед переводом на S3Например, они все изображения?Или все они в простом тексте.это нужно настроить на уровне политики создания корзины?Попытка передачи заголовков ObjectMetadata для "content_type_starts_with
" и "content_range
" безуспешно.ожидал, что S3 отклонит запрос на размещение, но он прошел успешно.
objectMetadata.setHeader("content_type_starts_with","image/");
objectMetadata.setHeader("content_range","1..100");
Вторая проблема, с которой сталкивается случайное получение преждевременного завершения исключений потока при итерации через поля неформ внутри IoUtils.toString ().Это происходит главным образом во время отладки или форсирования GC между итерациями.Хотя я имею S3Client как переменную класса, не уверен, что вызывает это исключение.Однако, если поток непосредственно считывается в String, а другой InputStream открывается из String, ошибка не возникает.
Преимущества вышеуказанного подхода, временное местоположение не используется, и память также сохраняется при загрузке файлов на S3, так как это операция записи в поток в поток.Также не используется multipart s3 api для загрузки, так как некоторые части имеют ограничение менее 5 МБ.Однако, любым способом мы можем исправить эти 2.
Наличие проверок типа проверок типа контента перед загрузкой на S3 или во время запроса на размещение.Я думаю, что политика S3 Bucket может помочь, но некоторые справки / примеры помогут
исправить ошибку преждевременного завершения потока при чтении объектов S3 с использованием заметок здесь https://commons.apache.org/proper/commons-fileupload/streaming.html