Retrofit for android #Multipart remove default headers - java

Making a #Multipart request adds these default headers (Content-Transfer-Encoding, Content-Type) for each part, is there any way to remove them?
//REQUEST BODY
--25d35373-d2c3-46a3-969f-f5a1fd5f781a
Content-Disposition: form-data; name="client_id"
Content-Transfer-Encoding: binary <-- remove this one
Content-Type: application/json; charset=UTF-8 <-- remove this one
Content-Length: 34
"40ccfee680a844780a41fbe23ea89934"
//
NOTE: I do not have access to the server so there is no way I will be able to make the server accept these headers.

You can build multipart body by your self in this way (kotlin code but same idea may be expressed with java):
val mpart = MultipartBody.Builder()
.addFormDataPart("param", paramValue)
.addPart(null, someRequestBody).build() // <-- (*) see explanation below
//thus, service method should looks like this:
#POST("upload/endpoint")
fun upload(#Body parts: MultipartBody)
(*) - this is the addPart(headers: Headers, reqBody: RequestBody) method, when you pass null to headers arg this removes all headers except Content-Length:

#POST(...)
suspend fun updateImage(#Body Body: RequestBody): Response<ResponseBody>
val uploadFile = File(...)
val bodyFile = uploadFile.asRequestBody("image/*".toMediaType())
val bodyBuilder = MultipartBody.Builder()
bodyBuilder.setType(MultipartBody.FORM)
bodyBuilder.addFormDataPart("img", uploadFile.name, bodyFile)
api.updateImage(bodyBuilder.build())
retrofit + coroutine

Related

Problems Sending FormUrlEncoded using Retrofit

I have this request and I need to send it by FormUrlEncoded using Retrofit
{
"clnt_id": "OQW",
"clnt_res": "AA!##$T",
"type": "SCDS",
"len": "ASD"
}
I used this code:
#FormUrlEncoded
#POST("Endpoint")
#Headers("Accept: Application/JSON")
fun connect(
#Field("clnt_id") clnt_id: String,
#Field(value = "clnt_res", encoded = false) clnt_res: String,
#Field("type") type: String,
#Field("len") len: String
): Observable<Token>
First, thing is that the request is not sent as JSON
Second, the value of "clnt_res", encoded by retrofit
You have 2 options to send json request from android using Retrofit.
Create Pojo Model of json request and pass it by setting values of it.
Create HashMap and pass it to request.
Here is solution using 2nd Method:
Create hashmap and put key(parameters) and value:
Map<String,String> requestMap = new HashMap<>();
requestMap.put("clnt_id","your_value");
requestMap.put("clnt_res","your_value");
requestMap.put("type","your_value");
requestMap.put("len","your_value");
Then pass it to your retrofit request using FieldMap:
#FormUrlEncoded
#POST("Endpoint")
#Headers("Accept: Application/JSON")
fun connect(
#FieldMap requestMap:Map<String,String>
): Observable<Token>
I finally get the answer and it was a problem with symbol '$' in 'clnt_res' value "AA!##$T", The problem is in kotlin to escape a special char you need to do this "\$", what I made the IDE didn't tell me that it is wrong is this "$/".

the difference between Postman and POST request in Java

I need to get some respones from some URL.
For this purpose I use http://unirest.io/java.html and Java.
Map<String, String> map = new HashMap<>();
map.put(key1, value1);
...
map.put(keyN, valueN);
String authToken = "{token}";
HttpResponse<String> response = Unirest.post(url)
.header("Authorization","Bearer " + authToken)
.header("Content-Type", "application/json")
.fields(map)
.asString();
As a result I receive response.getStatus() = 302 and some unexpected body.
At the same time I use Postman software to get the same responses. The settings are the following:
POST: url
Authorization: Type -> Bearer Token; Token = {{authToken}} // get the value from the previous request
Header :
"Authorization" : "Bearer " + {{authToken}}
Content-Type: application/json
Body:
{
key1 : value1,
...
keyN : valueN
}
And I get some expected response.
What makes the difference?
A 302 is a redirect response. Is it possible Postman is following the redirect and returning the resultant page? Take a look at the Location header in the response you get in Java, and see if following that gives you the same results you're seeing in Postman.

How to add headers of HTTP request to response

Sorry if the question is possibly repeated. I'm not familiar with Java and I'm stuck with a Cordova plugin which returns headers in a non-JSON structure which I think is Map.soString() presentation of request.headers()
//These parts works fine returning response body
HttpRequest request = HttpRequest.post(this.getUrlString());
this.setupSecurity(request);
request.headers(this.getHeaders());
request.acceptJson();
request.contentType(HttpRequest.CONTENT_TYPE_JSON);
request.send(getJsonObject().toString());
int code = request.code();
String body = request.body(CHARSET);
JSONObject response = new JSONObject();
response.put("status", code);
// in this line I must put JSON converted headers instead of request.headers()
response.put("headers", request.headers());
I've tried
String headers = request.headers().toString();
and
JSONObject headers = new JSONObject(request.headers());
to change the aforementioned line to
response.put("headers", headers);
but none of them worked.
How should I send headers as JSON in response?
More context:
Currently the response headers are:
{
null=[HTTP/1.0 200 OK],
Content-Type=[application/json],
Date=[Mon, 25 Jan 2016 07:47:31 GMT],
Server=[WSGIServer/0.1 Python/2.7.6],
Set-Cookie=[csrftoken=tehrIvP7gXzfY3F9CWrjbLXb2uGdwACn; expires=Mon, 23-Jan-2017 07:47:31 GMT; Max-Age=31449600; Path=/, sessionid=iuza9r2wm3zbn07aa2mltbv247ipwfbs; expires=Mon, 08-Feb-2016 07:47:31 GMT; httponly; Max-Age=1209600; Path=/],
Vary=[Accept, Cookie],
X-Android-Received-Millis=[1453708294595],
X-Android-Sent-Millis=[1453708294184], X-Frame-Options=[SAMEORIGIN]
}
and are sent in body of response. so I need to parse them, but I can't do.
This should be the way to do it:
JSONObject headers = new JSONObject(request.headers());
However, the "toString()" display of the headers seem to be showing a map entry with a null key. That won't work in JSON: an JSON object attribute name cannot be null. My guess is that the null key caused the crash.
So I think you need to filter out the "bad" entry; i.e. code it something like this:
JSONObject headers = new JSONObject()
for (Map.Entry entry: request.headers().entries()) {
if (entry.getKey() != null) {
headers.put(entry.getKey(), entry.getValue());
}
}

Why are my headers null after a POST?

I'll lay down my code first: Note: I also have log output at the bottom of the question.
Server Side:
#Post
#Consumes("application/octet-stream")
public Representation post(InputStream zip, #HeaderParam(value = "Content-Disposition") HttpHeaders headers) throws Throwable {
System.out.println(headers); //Prints null - want the header to not be null here
String uploadedFileLocation = getStartingDir() + "/" + "abc.zip";
writeToFile(zip, uploadedFileLocation);
return new StringRepresentation("Uploaded!");
}
Client Side:
public static void main(String[] args) throws Exception {
final String BASE_URI = "http://localhost:8080/server/upload";
Client client = Client.create();
WebResource service = client.resource(BASE_URI);
client.setChunkedEncodingSize(1024);
client.addFilter(new LoggingFilter());
File zip = new File("C:/Users/sdery/Desktop/abc.zip");
InputStream fileInStream = new FileInputStream(zip);
String sContentDisposition = "attachment; filename=\"" + zip.getName()+"\"";
ClientResponse response = service.header("Authorization", "Basic xxx=").header("Content-Disposition", (Object)sContentDisposition).type(MediaType.APPLICATION_OCTET_STREAM).post(ClientResponse.class, fileInStream);
System.out.println("Response Status : " + response.getEntity(String.class));
}
First off, the file transfer works, I'm happy. However, I would like to get the headers on the server side so I don't have to hard code the file name. Any ideas as to why it is comin' up null? Does it have to do with me using ClientResponse instead of ClientRequest?
Jul 31, 2013 8:44:12 AM com.sun.jersey.api.client.filter.LoggingFilter log
INFO: 1 * Client out-bound request
1 > POST http://localhost:8080/server/upload
1 > Content-Disposition: attachment; filename="abc.zip"
1 > Authorization: Basic xxx=
1 > Content-Type: application/octet-stream
(zip bytes)
INFO: 1 * Client in-bound response
1 < 200
1 < Date: Wed, 31 Jul 2013 12:44:12 GMT
1 < Date: Wed, 31 Jul 2013 12:44:12 GMT
1 < Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
1 < Content-Length: 88
1 < Set-Cookie: rememberMe=deleteMe; Path=/server; Max-Age=0; Expires=Tue, 30-Jul-2013 12:44:12 GMT
1 < Content-Type: text/plain; charset=UTF-8
1 < Accept-Ranges: bytes
1 < Server: Restlet-Framework/2.0.4
1 < Real-Token: bar
1 <
Uploaded!
From the log output, it seems that the header containing Content-Disposition is there. Does this mean I should be able to retrieve the value from the server side code?
You're parameter is of the wrong type. You should declare the parameter as a String. HttpHeaders is for getting all the headers and is annotated with a #Context. #HttpParam can only be converted to a limited number of types.
From the Jersey documentation for HeaderParam.
Binds the value(s) of a HTTP header to a resource method parameter, resource class field, or resource class bean property. A default value can be specified using the DefaultValue annotation. The type T of the annotated parameter, field or property must either:
Be a primitive type
Have a constructor that accepts a single String argument
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String))
Be List<T>, Set<T> or SortedSet<T>, where T satisfies 2 or 3 above. The resulting collection is read-only.
So you're code would be more like
#Post
#Consumes("application/octet-stream")
public Representation post(InputStream zip, #HeaderParam(value = "Content- Disposition") String contentDisposition) throws Throwable {
System.out.println(contentDisposition);
String uploadedFileLocation = getStartingDir() + "/" + "abc.zip";
writeToFile(zip, uploadedFileLocation);
return new StringRepresentation("Uploaded!");
}
First off, I apologize that my solution is from a JavaScript/PHP reference and not Java, but I believe your solution may be similar.
Add a new header named 'X-FILENAME' and set the name of your file as the header data. I believe your code would look something like this:
ClientResponse response = service.header("X-FILENAME", "abc.zip");
Then, on your server, you should be able to retrieve that header param (In PHP it is the $_SERVER global, it looks like in yours it may be #HeaderParam).
Also, for reference just in case this applies to you, in PHP when you retrieve the header param you need to use a modified param name by adding 'HTTP_' to the front and changing all dashes to underscores like this 'HTTP_X_FILENAME'. So on the client you sent 'X-FILENAME' while on the server you retrieve that same value with 'HTTP_X_FILENAME'.
I hope this leads you in the right direction.

In Java, how to set the header of a Restlet Response?

I can't seem to figure out how to add headers to my restlet response. When I look at the available methods in the Response object, all I see is setStatus, setEntity, and setAttributes but none of these tell me how to set custom http headers on the response.
For example, I have a GET call the returns something like the following:
HTTP/1.1 200 OK
Content-Type: text/json
Content-Length: 123
Some-Header: the value
Some-Other-Header: another value
{
id: 111,
value: "some value this could be anything",
diagnosis: {
start: 12552255,
end: 12552261,
key: "ABC123E11",
source: "S1",
}
}
Whatever it maybe. In the handleGet method, I handle it like so:
final MediaType textJsonType = new MediaType("text/json");
#Override
public void handleGet() {
log.debug("Handling GET...");
final Response res = this.getResponse();
try {
final MyObject doc = this.getObj("hello", 1, "ABC123E11", "S1");
final String docStr = doc.toString();
res.setStatus(Status.SUCCESS_OK);
res.setEntity(docStr, textJsonType);
// need to set Some-header, and Some-other-header here!
}
catch(Throwable t) {
res.setStatus(Status.SERVER_ERROR_INTERNAL);
res.setEntity(new TextRepresentation(t.toString()));
}
}
Because Restlet is more about the REST architectural principles than HTTP, it tries to be protocol agnostic and doesn't expose the HTTP headers directly. However, they are stored in the org.restlet.http.headers attribute of the response (as a Form). Note that you can only set custom headers this way, not standard ones (these are handled directly by the framework, e.g. Content-Type depends on the Representation's MediaType).
See this for an example:
http://blog.arc90.com/2008/09/15/custom-http-response-headers-with-restlet/ (link content also available from the Internet Archive Wayback Machine).

Categories

Resources