public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
There's only HttpRequestMessage parameter on the run() method in the Azure Functions(Java)
spec.
I need to declare and use MultipartHttpServletRequest to fetch a file from the multipart/data request.
I'm trying but cannot see any way to cast HttpRequestMessag
to MultipartHttpServletRequest
.
Please give me some advice.
The HttpTrigger spec is : https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation.httptrigger?view=azure-java-stable
----------------------- update -------------------------
The uploaded image is still corrupted. The size is exaclty same as the original one, but it seems like this :
I will paste the entire code. Please review it.
Function Class source :
public class HttpTriggerJava {
private static final String storageConnectionString =
"DefaultEndpointsProtocol=http;" +
"AccountName=00000;" +
"AccountKey=00000";
@FunctionName("HttpTriggerJava")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) throws Exception{
context.getLogger().info("Java HTTP trigger processed a request.");
CloudStorageAccount storageAccount = CloudStorageAccount.parse(storageConnectionString);
CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
CloudBlobContainer container = blobClient.getContainerReference("contents");
// here the "content-type" must be lower-case
String contentType = request.getHeaders().get("content-type"); // Get content-type header
String body = request.getBody().get(); // Get request body
String boundary = contentType.split(";")[1].split("=")[1]; // Get boundary from content-type header
int bufSize = 1024;
InputStream in = new ByteArrayInputStream(body.getBytes()); // Convert body to an input stream
MultipartStream multipartStream = new MultipartStream(in, boundary.getBytes(), bufSize, null); // Using MultipartStream to parse body input stream
boolean nextPart = multipartStream.skipPreamble();
while(nextPart) {
String header = multipartStream.readHeaders();
System.out.println("");
System.out.println("Headers:");
System.out.println(header);
System.out.println("Body:");
if (header.contains("Content-Type: image/")) {
int start = header.indexOf("filename=")+"filename=".length()+1;
int end = header.indexOf("\r\n")-1;
String filename = header.substring(start, end);
System.out.println(filename);
FileOutputStream fos = new FileOutputStream(filename);
multipartStream.readBodyData(fos);
File sourceFile = new File(filename);
CloudBlockBlob blob = container.getBlockBlobReference(filename);
blob.uploadFromFile(sourceFile.getAbsolutePath());
} else {
multipartStream.readBodyData(System.out);
}
System.out.println("");
nextPart = multipartStream.readBoundary();
}
return request.createResponseBuilder(HttpStatus.OK).body("Success").build();
}
}
And the HTML is :
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function () {
$("#myFile").change(function() {
readURL(this);
});
$("#submit").click(function (event) {
event.preventDefault();
var form = $('#form')[0];
var data = new FormData(form);
$("#submit").prop("disabled", true);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: $(form).attr('action'),
data: data,
processData: false,
contentType: false,
cache: false,
timeout: 600000,
success: function (data) {
$("#result").text(data);
console.log("SUCCESS : ", data);
$("#submit").prop("disabled", false);
},
error: function (e) {
$("#result").text(e.responseText);
console.log("ERROR : ", e);
$("#submit").prop("disabled", false);
}
});
});
});
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#blah').attr('src', e.target.result).show();
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
</head>
<body>
<form id=form
action="http://doopediafunctiontest.azurewebsites.net/api/HttpTriggerJava?code=00000"
method="post" enctype="multipart/form-data">
<p>
<br /> <br /> <strong>My file:</strong><br /> <input type="file" id="myFile" name="myFile">
<br /><img id="blah" src="#" alt="your image" style="display:none" />
</p>
<input id=submit type="submit" value="upload to Blob Storage">
</form>
<div id=result></div>
</body>
I compare the original image and the corrupted image by a hex editor.
And I found some random hexes changed to 3f
, it should be the reason. Maybe there's some encoding problem. But how can I fix this?
It sounds like you want to upload a file to your Azure Function with Http Trigger in Java via a HTML form with
multipart/form-data
like below.However, there is not any class implements the interface
HttpRequestMessage<T>
and seems to not castHttpRequestMessage
toHttpServletRequest
after I researched the source code of GitHub RepoAzure/azure-functions-java-library
.Per my experience, the only way is to parse the header and body of a
multipart/form-data
request to get the file. There is an answer of the similar SO thread Library and examples of parsing multipart/form-data from inputstream posted by the question owner, which includes the code usingMultipartStream
class of Apache Commons FileUpload that works after I test it.Here is the
Content-Type
header and body of amultipart/form-data
request received from Azure Function for Java.Header
Content-Type
multipart/form-data
request bodyHere is my sample code to fetch the file.
The output of code above in terminal :
Update: If upload an image, the output of the code above is like below.
So you can parse the header to get the
filename
value to useFileOutputStream
to store it, as the code below.Update 2:
I discovered there seems to be an issue of Azure Function for Java which may be a bug that will lose some bytes when uploading binary file, but it will not happend for uploading text file. So a workaround solution is to convert upload file to base64 string in browser to post to Azure Function and convert base64 content uploaded to the origin binary file in Azure Function.
Here is my testing HTML code.
The form above will post the header and body of base64 file chunk as below.
My Java code in Azure Function: