Hi I'm newbie in android!
I want to upload image file from android client to server(Server makes thumbnail, and return thumbnail's url).
However I stucked in this error message.
{"errorMessage":"RequestId: 8e2a21b8-e62e-11e8-8585-d9b6fdfec9b9 Process exited before completing request"}!
I tried to find this error code in stackoverflow, but i cannot found answer for android.
Please help or give me link where I can solve this problem...
Here is server code.
const AWS = require('aws-sdk');
const multipart = require("parse-multipart");
const s3 = new AWS.S3();
const bluebird = require('bluebird');
exports.handler = function(event, context) {
let result = [];
const bodyBuffer = new Buffer(event['body-json'].toString(), 'base64');
const boundary = multipart.getBoundary(event.params.header['Content-Type']);
const parts = multipart.Parse(bodyBuffer, boundary);
const files = getFiles(parts);
return bluebird.map(files, file => {
console.log('UploadCall');
return upload(file)
.then(
data => {
result.push({
'bucket': data.Bucket,
'key': data.key,
'fileUrl': file.uploadFile.fullPath })
console.log( `DATA => ${JSON.stringify(data, null, 2 )}`);
},
err => {
console.log(`S3 UPLOAD ERR => ${err}`);
}
)
})
.then(_=> {
return context.succeed(result);
});
}
let upload = function(file) {
console.log('PutObject Call')
return s3.upload(file.params).promise();
};
let getFiles = function(parts) {
let files = [];
parts.forEach(part => {
const buffer = part.data
const fileName = part.filename;
const fileFullName = fileName;
const originBucket = 'dna-edge/images';
const filefullPath = `https://s3.ap-northeast-2.amazonaws.com/${originBucket}/${fileFullName}`;
const params = {
Bucket: originBucket,
Key: fileFullName,
Body: buffer
};
const uploadFile = {
size: buffer.toString('ascii').length,
type: part.type,
name: fileName,
fullPath: filefullPath
};
files.push({ params, uploadFile })
});
return files;
};
And this is client code.(imgURL looks like /storage/emulated/0/DCIM/img/1493742568136.jpg)
public static String requestHttpPostLambda(String url, String imgURL){
/*
await axios.post(`${AWS_LAMBDA_API_URL}?type=${type}`, formData,
{ headers: { 'Content-Type': 'multipart/form-data' }})
.then((response) => {result = response});
*/
String result=null;
try {
HttpClient client = new DefaultHttpClient();
String postURL = url;
HttpPost post = new HttpPost(postURL);
post.setHeader("Content-Type", "multipart/form-data");
File file = new File(imgURL);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("image", new FileBody(file));
post.setEntity(builder.build());
HttpResponse responsePOST = client.execute(post);
Log.e("HttpResponse", responsePOST.getStatusLine()+"");
HttpEntity resEntity = responsePOST.getEntity();
if (resEntity != null) {
result = EntityUtils.toString(resEntity);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Welcome to stackoverflow.
So for some reason AWS aren't too good an updating the docs, don't use context.succeed, use the callback thats passed as a third param.
Also I'd move to Node 8.10 runtime because then rather than using promises/then pattern you can use async/await.
export default(event, context, callback) => {
try {
// do some stuff
callback(null, SOME_VALID_HTTP_RESPONSE)
} catch(e){
callback(e, null)
}
}
There's a few reason your Lambda could be failing, if the process exited before completing it's either crashing OR you're not returning a valid HTTP response(if your lambda is behind API gateway)
Two solutions - first place to look is in cloudwatch, find your lambda function name and check the latest log to look for error messages.
Second - check out my answer here so when your function succeeds you need to return a valid HTTP response to API Gateway so in essence if you use my code from there you can do:
callback(null, responder.success({someJson: someValue}))
Any questions let me know :-)
EDIT: I'm updating this question I'm just working on an example for a multiple file upload to S3!
Related
I am uploading a file using MultipartRequest from package:http. I am successfully uploading the file but I want to get the progress of the file that is being uploaded. How can I achieve that? My current code looks something like this
Future submitFile(var report, File file) async {
var uri = Uri.parse(endpoint + "v1/reports");
var request = http.MultipartRequest("POST", uri);
await addHeaders(request.headers);
request.fields.addAll(Report.toMap(report));
if (file != null)
request.files.add(await http.MultipartFile.fromPath(
'report_resource',
file.path,
));
String response = "";
await (await request.send()).stream.forEach((message) {
response = response + String.fromCharCodes(message);
});
return response;
}
I searched for the solution, found this. And this post is somehow not similar to what I want to achieve, as he is using different client for the request.
Maybe I am not searching on the right path.
Help is appreciated.
Here is my take:
// multipart_request.dart
import 'dart:async';
import 'package:http/http.dart' as http;
class MultipartRequest extends http.MultipartRequest {
/// Creates a new [MultipartRequest].
MultipartRequest(
String method,
Uri url, {
this.onProgress,
}) : super(method, url);
final void Function(int bytes, int totalBytes) onProgress;
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
/// that will emit the request body.
http.ByteStream finalize() {
final byteStream = super.finalize();
if (onProgress == null) return byteStream;
final total = this.contentLength;
int bytes = 0;
final t = StreamTransformer.fromHandlers(
handleData: (List<int> data, EventSink<List<int>> sink) {
bytes += data.length;
onProgress(bytes, total);
if(total >= bytes) {
sink.add(data);
}
},
);
final stream = byteStream.transform(t);
return http.ByteStream(stream);
}
}
Usage:
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart' show MediaType;
import 'multipart_request.dart';
final uri = 'https://...';
final request = MultipartRequest(
'POST',
uri,
onProgress: (int bytes, int total) {
final progress = bytes / total;
print('progress: $progress ($bytes/$total)');
},
);
request.headers['HeaderKey'] = 'header_value';
request.fields['form_key'] = 'form_value';
request.files.add(
await http.MultipartFile.fromPath(
'field_name',
'path/to/file',
contentType: MediaType('image', 'jpeg'),
),
);
final streamedResponse = await request.send();
After waiting for a week or so. I didn't get response. Thus I developed a plugin myself to get this behavior. Package link.
Example to use it:
var request = MultipartRequest();
request.addFile("image", imagePath);
Response response = request.send();
response.onError = () {
print("Error");
};
response.onComplete = (response) {
print(response);
};
//Not 100% success
response.progress.listen((int progress) {
print("progress from response object " + progress.toString());
});
Update Jun 30, 2020
The package now supports iOS as well.
Can you try this class as I did not test it yet, Let me know of any thing printed in your console.
class MF extends http.MultipartRequest{
MF(String method, Uri url) : super(method, url);
#override
Future<http.StreamedResponse> send() async {
var client = new Client();
int byteCount = 0;
Stream<List<int>> onDone<T>(Stream<List<int>> stream, void onDone()) =>
stream.transform(new StreamTransformer.fromHandlers(
handleDone: (sink) {
sink.close();
onDone();
},
handleData: (data, sink) {
byteCount += data.length;
print(byteCount);
sink.add(data);
},
),
);
try {
var response = await client.send(this);
var stream = onDone(response.stream, client.close);
return new StreamedResponse(new ByteStream(stream), response.statusCode,
contentLength: response.contentLength,
request: response.request,
headers: response.headers,
isRedirect: response.isRedirect,
persistentConnection: response.persistentConnection,
reasonPhrase: response.reasonPhrase);
} catch (_) {
client.close();
rethrow;
}
}
}
USAGE:
instead of var request = http.MultipartRequest("POST", uri);
use:
var request = MF("POST", uri);
I am trying to upload multiple image in server using android application which is builds with flutter language. Here is the code which I am trying.
static Future postDataWithFile(......List<File> images) async {
Map<String, String> headers = {
"Accept": "application/json",
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer $token',
};
var request = http.MultipartRequest('POST', Uri.parse(url));
request.headers.addAll(headers);
request.fields['contact'] = insertVisitedPlace.contact;
request.fields['ownerName'] = insertVisitedPlace.ownerName;
request.fields['orgName'] = insertVisitedPlace.orgName;
request.fields['orgtype'] = insertVisitedPlace.orgType.toString();
request.fields['nextFollowup'] = insertVisitedPlace.nextFollowup ?? "";
..............................
Here I am use a List to store all image.
List<MultipartFile> allImagesAfterConvert = [];
images.forEach((image) {
allImagesAfterConvert.add(
await http.MultipartFile.fromPath(
'orgImages',
image.path,
)
);
});
Send request to server to add all images. But In the server get only one image.
request.files.addAll(allImagesAfterConvert);
try {
final response = await request
.send()
.timeout(Duration(seconds: timeoutSeconds), onTimeout: () {
throw TimeoutException("Connection time out. Please try again");
});
return _isValidResponse(response) ? response : _error(response);
} on SocketException {
throw Failure("No Internet Connection");
} on TimeoutException {
throw Failure("Request time out");
} on Error catch (e) {
throw Failure(e.toString());
}
}
Replace orgImages with orgImages[]
images.forEach((image) {
allImagesAfterConvert.add(
await http.MultipartFile.fromPath(
'orgImages[]’,
image.path,
)
);
});
This should work.
i using the ImagePicker package in the dart when i pick the image i want to upload this to the server with the form data but when i try to send this i give this error
" Unhandled Exception: FileSystemException: Cannot retrieve length of file, path = 'File: '/storage/emulated/0/Android/data/com.example.aloteb/files/Pictures/scaled_image_picker3594752094355545880.jpg'' "
and this is my code for sending to the server
var request = http.MultipartRequest('POST', Uri.parse(url));
request.fields.addAll({
'data': '$map'
});
request.files.add(await http.MultipartFile.fromPath('image',picproviderformdate.getPAth.toString()));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
and this is my ImagePickercode
picprovider pic = Provider.of<picprovider>(context,listen: false);
File image = await ImagePicker.pickImage(
source: ImageSource.gallery, imageQuality: 50);
setState(() {
_image = image;
});
print(_image);
pic.setpathe(_image);
can any one help me for solve this problem?
I had a similar problem a while ago, and i used the Dio dependency instead of the classical Http link.
The code is very similar, and i can gave you an example.
final File file = File("${documentDirectory.path}/picture.png");
final httpDio = dio.Dio();
final formData = dio.FormData.fromMap({
"data": "{}",
"files.image": await dio.MultipartFile.fromFile(
"${documentDirectory.path}/picture.png",
filename: "picture.png",
contentType: MediaType('image', 'png'))
});
try {
final dio.Response response = await httpDio.post(
"ApiEndpoint/avatars",
data: formData,
options: dio.Options(headers: {"Authorization": "Bearer yourTokenIfNeeded"}));
if (response.statusCode == 200) {
// Success
}
} on dio.DioError catch (e) {
if (e.response != null) {
// Error
print(e.response.data);
return;
}
}
Don't forgot to update the API endpoint and route as well as your auth authorization if you need one.
I'm recreating a project that was originally designed for Native Android to use React Native. There is an endpoint that is responsible to send a image using Form Data. I tried to convert the OkHttp3's Form Data to Axios's Form Data and I'm getting an error from backend saying that the request fields doesn't match.
My Code so far:
- Native Android(original app):
public RequestResponse<Boolean> functionApi(#NonNull String id, String imageExtension, #NonNull byte[] imageData, #NonNull String anotherData) throws ServerErrorException, IOException, AuthenticationException {
String path = "route/" + id;
Pair<String, String> contentTypeHeader = new Pair<>("Content-Type", "multipart/form-data");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("anotherData", anotherData)
.addFormDataPart("imageData", id + "." + imageExtension, RequestBody.create(MediaType.parse("image/png"), imageData))
.build();
Response response = MyHttpClient.execute(path, "POST", requestBody, contentTypeHeader);
String body = response.body().string();
RequestResponse<Boolean> r = responseBodyToObject(body, RequestResponse.class);
r.setBody(r.getStatus() != RequestResponse.ERROR);
return r;
}
React Native(new app) version:
export const functionApi = async(id,imageExtension,imageData,anotherData)=>{
try{
let formData = new FormData()
formData.append('anotherData',anotherData)
formData.append('imageData',`data:image/${imageExtension};base64,${imageData}`,`${id}.${imageExtension}`)
//imageData here i tried to use a base64's string
let res = await axios({
url:`${URL_SERVER}/route/${id}`,
method:'POST',
headers:{
'Content-Type':"multipart/form-data"
},
data:formData
})
return res['data']
}catch(err){
return getErrorMessage(err)
}
}
I got a solution that finally worked for me:
export const functionApi = async(id,imageExtension,imageData,anotherData)=>{
try{
let formData = new FormData()
formData.append('anotherData',anotherData)
formData.append('imageData',{
uri: imageData['uri'],
type: 'image/jpg',
name: `${id}.${imageExtension}`,
})
let res = await axios({
url:`${URL_SERVER}/route/${id}`,
method:'POST',
headers:{
'Content-Type':'multipart/form-data'
},
data:formData
})
return res['data']
}catch(err){
return getErrorMessage(err)
}
}
The class APIPostRequest was wroking all fine until a flutter upgrade hit and it shows an error of "The argument type 'Utf8Decoder' can't be assigned to the parameter type 'StreamTransformer'." while transforming HttpClientResponse's object into String using ...transform(utf8.decoder)...
class APIPostRequest {
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('Accept', 'application/json');
request.headers.set('Content-type', 'application/json');
request.headers
.set('Authorization', "Bearer " + UserConstants.userAccessToken);
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
String reply = await response.transform(utf8.decoder).join();
httpClient.close();
return reply;
}
}
See the corresponding breaking change announcement:
Error cases (and how to fix them):
If you see the following errors in your code, here's what you do to fix them:
Error: "The argument type 'Utf8Decoder' can't be assigned to the parameter type 'StreamTransformer'."
How to fix: Use StreamTransformer.bind(Stream) instead of Stream.transform(StreamTransformer).
Example:
Before: foo.transform(utf8.decoder)...
After: utf8.decoder.bind(foo)...
Comment String reply = await utf8.decoder.bind(response).join();
and use the following code :
//String reply = await response.transform(utf8.decoder).join();
String reply;
request.close().then((response){
response.cast<List<int>>().transform(utf8.decoder).listen((content) {
print (content);
reply = content;
});
See below solution
class APIPostRequest {
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('Accept', 'application/json');
request.headers.set('Content-type', 'application/json');
request.headers
.set('Authorization', "Bearer " + UserConstants.userAccessToken);
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
String reply = await utf8.decoder.bind(response).join();
httpClient.close();
return reply;
}
}