I sent image file and content (text) using retrofit from android client and tried to get them in the server side but can not do that and the error is always : it is null.
Please how can I send image and receive it using #Retrofit and Slim framework?
If anyone can help, I will appreciate.
..............................................
Tried to send the image from android client like a multipart file and receive it with slim using method (getUploadedFiles) and it didn't work.
#Multipart
#POST("createPostWithImage")
Call<DefaultResponse> uploadTestPost(
#Part("desc") RequestBody desc,
#Part MultipartBody.Part image
);
$app-> post('/createPostWithImage', function(Request $request, Response $response) {
$directory = __DIR__.'../photos/1';
$uploadedFiles = $request->getUploadedFiles();
$uploadedFile = $uploadedFiles['photo'];
$uploadedFile->moveTo($directory);
});
get the file which was sent from android client and save it into specific folder.
$app->post('/file', function($request,$response) {
try{
$directory = $this->get('upload_directory');
$uploadedFiles = $request->getUploadedFiles();
$uploadedFile = $uploadedFiles['example1'];
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
$basename = mt_rand(10000000, 99999999);
$uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $basename.'.'.$extension);
return $response->withJson(array('message' =>$uploadedFile),200);
}
catch(\Exception $ex){
return $response->withJson(array('error' => $ex->getMessage()),422);
}
});
//minimal code to get started ...
Related
I'm trying to upload an image to an http server that supposedly accepts files in "the standard way", whatever that means. I've combined a bunch of examples from the Internet, each of which does a tiny part of what I want, into this solution.
'srcBitmap' is a byteArray containing the JPG data.
val response: HttpResponse = httpClient.submitFormWithBinaryData(
url = URLUploadFile,
formData = formData {
append("bitmapName", "image.jpg")
append("image", srcBitmap, Headers.build {
append(HttpHeaders.ContentType, "image/jpg")
append(HttpHeaders.ContentDisposition, "filename=image.jpg")
})
},
block = {
headers {
append(HttpHeaders.ContentType, contentTypeString)
append(HttpHeaders.CacheControl, "no-cache")
append("my-app-authtoken", PREFKEY_AUTHTOKEN)
append("my-app-id", PREFKEY_USERID)
}
contentType(ContentType.Application.Json)
body = jsonBody.toString()
})
The main "body" part is some json that gets passed in the 'block' parameter. This data is arriving safely as intended.
But the binary data of the image itself is either not showing up on the server side, or is being ignored by the server because I don't have some "key" value set appropriately.
Is this the correct way to upload a file using Ktor? And if not, what am I doing wrong?
The second append call is a correct way of sending a part with the name image and the filename image.jpg. The problem is that you can't send both application/json and multipart/form-data content in one request.
Actually yours is a correct way, I was facing the same problem with my back-end guy that he receives my request as a byteArray file and couldn't recognized. So what I did was specify the files directly to the body instead of using submitFormWithBinaryData, as below..
'srcBitmap' is a byteArray containing the JPG data.
httpClient.post<RESPONSE>(URL) {
headers {
append(HttpHeaders.Accept, ContentType.Application.Json)
}
body = MultiPartFormDataContent(
formData {
this.append(FormPart("bitmapName", "image.jpg"))
this.appendInput(
key = "image",
headers = Headers.build {
append(
HttpHeaders.ContentDisposition,
"filename=image.jpg"
)
},
) { buildPacket { writeFully(srcBitmap) } }
}
)
}
I was having problem while saving picture in Django from Android app. I searched and finally solved the problem. I am sharing this so that it might help. Please see the answer below.
You will have to implement things according to your own specifications. I am just showing you as a generic example
I have used okHttp in my android app to send data on network (including pic)
Android AsyncTask Code (doInBackground Method)
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("filename","filename",RequestBody.create(MediaType.parse("multipart/form-data"), new File(file.getPath())))
//.addFormDataPart("other_field", "other_field_value")
.build();
Request request = new Request.Builder()
.header("Authorization", "Token " + myToken)
.url(myUrl).post(formBody).build();
Response response = new OkHttpClient().newCall(request).execute();
return response.body().string();
My view.py Code
def rechargeapplication(request):
user=#get your own object
uploadpic = request.FILES['filename']
user.picture.save("image.jpg",uploadpic)
user.save()
return JsonResponse({'result':'Success'})
How I created imageField in models.py
picture=models.ImageField(upload_to="photos" , null=True, blank=True)
if you are using ImageField then you will have to install "Pillow"
Also make sure that you specify MEDIA_ROOT & MEDIA_URL in settings.py....I am showing you how I did it
MEDIA_ROOT=os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'
and at the end of urls.py add this(as I was in debug mode that is why my implementation...)
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL,document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
Here's my problem: I'm writing a laravel backend which have to serve an mp3 file that had to be reproduced by using the android standard media player.
For the laravel backend I need to use JWT to handle authentication so on every request headers I have to set the "Authorization" field to "Bearer {token}" .The laravel route is "/songs/{id}" and is handled in this way:
public function getSong(Song $song) {
$file = new File(storage_path()."/songs/".$song->path.".mp3");
$headers = array();
$headers['Content-Type'] = 'audio/mpeg, audio/x-mpeg, audio/x-mpeg-3, audio/mpeg3';
$headers['Content-Length'] = $file->getSize();
$headers['Content-Transfer-Encoding'] = 'binary';
$headers['Accept-Range'] = 'bytes';
$headers['Cache-Control'] = 'must-revalidate, post-check=0, pre-check=0';
$headers['Connection'] = 'Keep-Alive';
$headers['Content-Disposition'] = 'attachment; filename="'.$song->path.'.mp3"';
$user = \Auth::user();
if($user->activated_at) {
return Response::download($file, $song->path, $headers);
}
\App::abort(400);
}
On the android side I'm using the MediaPlayer to stream the mp3 file in this way:
media_player = new MediaPlayer();
try {
media_player.setAudioStreamType(AudioManager.STREAM_MUSIC);
String token = getSharedPreferences("p_shared", MODE_PRIVATE).getString("token", null);
Map<String, String> headers = new HashMap<>();
headers.put("Authorization", "Bearer " + token);
media_player.setDataSource(
getApplicationContext(),
Uri.parse(ConnectionHelper.SERVER + "/songs/" + song.getId()),
headers
);
} catch (IOException e) {
finish();
Toast.makeText(
Round.this,
"Some error occurred. Retry in some minutes.",
Toast.LENGTH_SHORT
).show();
}
media_player.setOnCompletionListener(this);
media_player.setOnErrorListener(this);
media_player.setOnPreparedListener(this);
But every time I execute the code I get extra code -1005 on the error listener that means ERROR_CONNECTION_LOST.
The problem: Response::download(...) doesn't produce a stream, so I can't serve my .mp3 file.
The solution:
As Symfony HttpFoundation doc. says in the serving file paragraph:
"if you are serving a static file, you can use a BinaryFileResponse"
The .mp3 files I need to serve are statics in the server and stored in "/storage/songs/" so I decided to use the BinaryFileResponse, and the method for serving .mp3 became:
use Symfony\Component\HttpFoundation\BinaryFileResponse;
[...]
public function getSong(Song $song) {
$path = storage_path().DIRECTORY_SEPARATOR."songs".DIRECTORY_SEPARATOR.$song->path.".mp3");
$user = \Auth::user();
if($user->activated_at) {
$response = new BinaryFileResponse($path);
BinaryFileResponse::trustXSendfileTypeHeader();
return $response;
}
\App::abort(400);
}
The BinaryFileResponse automatically handle the requests and allow you to serve the file entirely (by making just one request with Http 200 code) or splitted for slower connection (more requests with Http 206 code and one final request with 200 code).
If you have the mod_xsendfile you can use (to make streaming faster) by adding:
BinaryFileResponse::trustXSendfileTypeHeader();
The android code doesn't need to change in order to stream the file.
I am posting the data from Android to the Node.js. I am successfully able to call the Node.js post method and using restify able to get the Post data.
But when doing through express I am not able to get the post body in Node.js. I tried for many approaches from SO post but it seems none are working may be I am missing something.
The snippets are like:
Node.js
var express = require('express')
var request = require('request')
var http = require('http')
var bodyParser = require('body-parser')
var app = express();
app.set('port', (process.env.PORT || 5000))
app.use(express.static(__dirname + '/public'))
app.use(bodyParser.urlencoded())
app.use(bodyParser.json())
app.post('/search/addcomplaint',addComplaint)
function addComplaint(req,res,next){
console.log(req.body);
if (!req.body) return res.sendStatus(400)
res.send(201,user)
}
app.listen(app.get('port'), function() {
console.log("Node app is running at localhost:" + app.get('port'))
})
at Android Site I am making a retrofit call like this:
#Multipart
#POST("/search/addcomplaint")
public User search(#Part("complaint") String complaint);
when I used restify in Node.js I was able to get req.body but using express I am not getting the request body.
I have the following controller set up:
#PreAuthorize("hasAuthority('ROLE_USER')")
#RequestMapping(value = "/me/avatar", method = RequestMethod.POST)
public #ResponseBody boolean setAvatar(Principal principal, MultipartHttpServletRequest request) {
String username = ((User) ((OAuth2Authentication) principal).getPrincipal()).getUsername();
MultipartFile file = request.getFile("avatar");
return Boolean.TRUE;
}
And when I use Square Retrofit to POST to this controller:
#Multipart
#POST("/user/me/avatar?access_token={access_token}")
void uploadAvatar(#Name("access_token") String accessToken, #Name("avatar") TypedFile image, retrofit.http.Callback<Boolean> callback);
I get a MultipartHttpServletRequest which has the "avatar" parameter, with the proper file name and everything, but no multipart files.
What am I doing wrong that would cause me to get MultipartParams but no MultipartFiles? I've tried various other TypedOutput formats, but I get the same result. If I hit the same controller from Postman (a Chrome plugin) everything works as expected, leading me to think it's a bug in Retrofit?
This was due to a bug in Retrofit, which has been fixed as of today. The above code now works to upload a file from Retrofit to a Spring based api server.