Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

%3F instead of question mark in my Retrofit URL

I'm trying to send a picture to a server. My URL contains some parameters about my phone:

api/v2/user/email_register%3F_height=1184&_target=android/2&_width=768 

and this is the working variant:

api/v2/user/email_register?_height=1184&_target=android/2&_width=768

(without irritation %3? code)

Also, I'm trying to pass my picture inside @Body:

@POST("/{url}")
Observable<UpdateUserInfoPayload> register(
        @Header("x-device-id") String deviceId,
        @Body RequestBody requestBody,
        @Path(value = "url", encoded = true) String  method
);

Creating it with MultipartBuilder:

protected RequestBody buildAvatar(String avatarPath) {


 MultipartBuilder builder = new MultipartBuilder()
  .type(MultipartBuilder.FORM)
  .addFormDataPart(ParkApiUrl.PARAM_USER_NAME, name.getText().toString())
  .addFormDataPart(ParkApiUrl.PARAM_USER_SECOND_NAME, lastName.getText().toString())
  .addFormDataPart(ParkApiUrl.PARAM_EMAIL, email.getText().toString())
  .addFormDataPart(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD,
   PasswordUtils.encodePassword(encodePassword()))
  .addFormDataPart(ParkApiUrl.PARAM_USER_GENDER,
   male.isChecked() ? EmailProfile.GENDER_MALE : EmailProfile.GENDER_FEMALE)
  .addFormDataPart(ParkApiUrl.PARAM_PARSE_ID,
   ParseInstallation.getCurrentInstallation().getObjectId());


 File file = new File(avatarPath);;
 int size = (int) file.length();
 byte[] bytes = new byte[size];
 try {
  BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
  buf.read(bytes, 0, bytes.length);
  buf.close();
  builder.addFormDataPart("photo", "image.jpg", RequestBody.create(MEDIA_TYPE_JPG, bytes));
 } catch (IOException e) {
  e.printStackTrace();
 }
 return builder.build();
}

That is why I'm unable to use for example:

@FieldMap Map<String, String> params

to pass my parameters there, because @FieldMap requires @FormUrlEncoded while I'm unable to make @Body request with @FormUrlEncoded.

1)How to remove %3F from my URL String? (outside retrofit everythin is fine!)

2)Is there any easy way to send a picture?

UPD: <-- 403 Forbidden https://api.example.com/api/v2/user/5984/validate_password when I use @Field annotation:

@FormUrlEncoded
@POST("/{url}")
Observable<BooleanResponse> validatePassword(
        @Header("x-device-id") String deviceId,
        @Field(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD) String password,
        @Field(ParkApiUrl.PARAM_HEIGHT) String height,
        @Field(ParkApiUrl.PARAM_WIDTH) String width,
        @Field(ParkApiUrl.PARAM_TARGET) String target,

        @Path(value = "url", encoded = true) String  method
);

Everything works when I use it like that:

@FormUrlEncoded
    @POST("/api/v2/user/5984/validate_password?_height=1184&_target=android%2F2&_width=768&_user_id=5984") //full url
    Observable<BooleanResponse> validatePassword(
            @Header("x-device-id") String deviceId,
            @Field(ParkApiUrl.PARAM_USER_ENCODED_PASSWORD) String password
    );

I want either to remove %3F or learn how to use Field in POST request without getting FORBIDDEN

like image 753
nutella_eater Avatar asked Apr 05 '16 06:04

nutella_eater


People also ask

How do you put a question mark in a URL?

The question mark ("?", ASCII 3F hex) is used to delimit the boundary between the URI of a queryable object, and a set of words used to express a query on that object. When this form is used, the combined URI stands for the object which results from the query being applied to the original object.

What does question mark mean in HTTP?

In a URL, the question mark (“?”) divides the address of an object and the set of words used in the query.

What is sent after the question mark in the URL?

It's the query, or sometimes the query string.


2 Answers

Retrofit won't let you put the query string in the path. Take a look at @QueryMap instead, which is designed for this.

like image 193
Jesse Wilson Avatar answered Oct 06 '22 06:10

Jesse Wilson


As refs: https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/QueryMap.html

I use @QueryMap and ImmutableMap.

In my case, the API is: /api/static_pages/?q=A+B+C

My solution:

Step 1:

@GET("/api/static_pages")
    Call<String> getStaticPagesByType(@HeaderMap HashMap<String, Object> header,
                               @QueryMap(encoded=true) Map<String, String> filters);

Step 2: When I want to call API:

List<String> listTypes = new ArrayList<>();
listTypes.add("A");
listTypes.add("B");
listTypes.add("C");

StringBuilder typeString = new StringBuilder();

int listSize = listType.size();

for (int i = 0; i < listSize - 1; i++) {
    typeString.append(listType.get(i));
    if(i != listSize-2){
       typeString.append("+");
    }
}
// The key is here!
ImmutableMap<String, String> types = ImmutableMap.of("q", typeString.toString());
getRetrofitClient().getStaticPagesByType(yourHeader, types)

Hope it help your work.

Happy coding.

like image 40
quan duong Avatar answered Oct 06 '22 05:10

quan duong