New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

method POST must have a request body. #854

Closed
crossle opened this Issue May 20, 2015 · 35 comments

Comments

@crossle

crossle commented May 20, 2015

Why?

compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'
                     D  java.lang.IllegalArgumentException: method POST must have a request body.
                        D      at com.squareup.okhttp.Request$Builder.method(Request.java:236)
                        D      at retrofit.client.OkClient.createRequest(OkClient.java:59)
                        D      at retrofit.client.OkClient.execute(OkClient.java:53)
                        D      at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:326)
                        D      at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220)
                        D      at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278)
                        D      at retrofit.CallbackRunnable.run(CallbackRunnable.java:42)
                        D      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                        D      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                        D      at retrofit.Platform$Android$2$1.run(Platform.java:142)
                        D      at java.lang.Thread.run(Thread.java:818)
@crossle

This comment has been minimized.

crossle commented May 21, 2015

@RahulRvR

This comment has been minimized.

RahulRvR commented May 21, 2015

@beshkenadze

This comment has been minimized.

beshkenadze commented May 22, 2015

👍
Here is changes: https://github.com/square/okhttp/blob/master/okhttp/src/main/java/com/squareup/okhttp/Request.java#L244

Temporary solution: downgrade OkHttp to version 2.3.0.

@crossle

This comment has been minimized.

crossle commented May 23, 2015

I used OkHttp 2.3.0, report this error

@beshkenadze

This comment has been minimized.

beshkenadze commented May 23, 2015

@crossle Maybe the dependencies was getting a newer version of the library.
In 2.3 there is no checking: https://github.com/square/okhttp/blob/parent-2.3.0/okhttp/src/main/java/com/squareup/okhttp/Request.java#L236

@RobertoArtiles

This comment has been minimized.

Contributor

RobertoArtiles commented May 26, 2015

As a reference: square/okhttp#751

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Jun 4, 2015

This is fixed on master by #875.

@JakeWharton JakeWharton closed this Jun 4, 2015

@myanimal

This comment has been minimized.

myanimal commented Jun 8, 2015

@JakeWharton any idea when we'll see this fix in a release?

@Defuera

This comment has been minimized.

Defuera commented Jun 9, 2015

I solved this issue by replacing @query to @field, heres how:

Not working code:

@post("/my/url/path")
Result postToServer(
@query("user_name") String userName);

Working example:

@FormUrlEncoded
@post("/my/url/path")
Result postToServer(
@field("user_name") String userName);

@beshkenadze

This comment has been minimized.

beshkenadze commented Jun 9, 2015

@Defuera This is not a solution, it use POST variables instead of GET variables.

@wahidm

This comment has been minimized.

wahidm commented Jun 12, 2015

Do you have an update on when a release will be available with this fix?

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Jun 12, 2015

No. You can add an empty body yourself with @Body String body and pass an empty string as a workaround.

@viniciuscb

This comment has been minimized.

viniciuscb commented Jun 12, 2015

same problem for me, it was working yesterday, not today anymore.

@antocara

This comment has been minimized.

antocara commented Jun 19, 2015

compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.4.0'

Today same problem, but the solution of Jake all ok, "@Body String body"

@beshkenadze

This comment has been minimized.

beshkenadze commented Jun 23, 2015

@anpstudio try downgrade to 2.3.0.

@IgorGanapolsky

This comment has been minimized.

IgorGanapolsky commented Jul 2, 2015

I am having the same problem since upgrading to Retrofit 1.9.0 (with OkHttp 2.4.0)

@ChocolateMinht

This comment has been minimized.

ChocolateMinht commented Aug 21, 2015

Had the same issue with Retrofit 1.9.0 + OkHttp 2.4.0. Downgrading to OkHttp 2.3.0 temporarily resolves the issue.

@WOSHICAIXIANFENG

This comment has been minimized.

WOSHICAIXIANFENG commented Aug 24, 2015

compile 'com.squareup.okhttp:okhttp:2.3.0'
Error:(36, 13) Failed to resolve: com.squareup.okhttp:okhttp:2.3.0

@martin-gearzero

This comment has been minimized.

martin-gearzero commented Sep 4, 2015

This is still an issue in 2.5.0:

compile 'com.squareup.okhttp:okhttp-urlconnection:2.5.0'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'com.squareup.retrofit:retrofit:1.9.0'

Curiously the OkHttp changelog for v2.4.0 says:

• "Fix: OkApacheClient now allows an empty PUT and POST."

This seems to be the version in which the error started since v2.3.0 works fine.

@dlew

This comment has been minimized.

Contributor

dlew commented Sep 11, 2015

The workaround is to use an empty body, but using @Body String empty wasn't working for me due to using a Gson converter. As a result, it was literally sending "" (i.e., two characters) instead of nothing.

The solution was to use a TypedOutput as the body. I setup this empty output:

class EmptyOutput implements TypedOutput {

    public static final TypedOutput INSTANCE = new EmptyOutput();

    private EmptyOutput() { }

    @Override
    public String fileName() {
        return null;
    }

    @Override
    public String mimeType() {
        return "application/json";
    }

    @Override
    public long length() {
        return 0;
    }

    @Override
    public void writeTo(OutputStream out) throws IOException {

    }
}

Then I can use it in the method signature:

@POST("/some/url)
Observable<Thing> doThing(@Body TypedOutput empty);

Then I call it using my instance:

service.doThing(EmptyOutput.INSTANCE);
@abhishek-ucreate

This comment has been minimized.

abhishek-ucreate commented Oct 21, 2015

downgrading to okhttp2.3 worked for me

@waqary705

This comment has been minimized.

waqary705 commented Nov 9, 2015

compile 'com.squareup.retrofit:retrofit:1.9.0'
Solution

include in @post Methods
@Body String anyString,

@WonderCsabo

This comment has been minimized.

WonderCsabo commented Nov 25, 2015

By extending #854 (comment) solution, you can create the following client:

package your.package;

import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.internal.http.HttpMethod;

import java.io.IOException;
import java.io.OutputStream;

import retrofit.client.OkClient;
import retrofit.client.Request;
import retrofit.client.Response;
import retrofit.mime.TypedOutput;

/**
 * Workaround for https://github.com/square/retrofit/issues/854 .
 */
public class NullBodyAwareOkClient extends OkClient {

    public NullBodyAwareOkClient() { }

    public NullBodyAwareOkClient(OkHttpClient okHttpClient) {
        super(okHttpClient);
    }

    @Override
    public Response execute(Request request) throws IOException {
        if (HttpMethod.requiresRequestBody(request.getMethod()) && request.getBody() == null) {
            Request newRequest = new Request(request.getMethod(), request.getUrl(), request.getHeaders(), EmptyOutput.INSTANCE);
            return super.execute(newRequest);
        }

        return super.execute(request);
    }

    private static class EmptyOutput implements TypedOutput {

        static final TypedOutput INSTANCE = new EmptyOutput();

        private EmptyOutput() { }

        @Override
        public String fileName() {
            return null;
        }

        @Override
        public String mimeType() {
            return "application/json";
        }

        @Override
        public long length() {
            return 0;
        }

        @Override
        public void writeTo(OutputStream out) throws IOException {

        }
    }
}

Then use it in your RestAdapter.Builder:

new RestAdapter.Builder()
                .setClient(new NullBodyAwareOkClient())
               // ...

This way you can get rid of the dummy @Body parameters in your API methods.

@yoganlegendkiller

This comment has been minimized.

yoganlegendkiller commented Dec 8, 2015

Am using retrofit 1.9.0 along with okhttp 2.4.0 is there any default json converter for retrofit 1.9 am making async call in interface but when in try to implement it throws service method cannot return void don't know where am doing mistake

@vovkab

This comment has been minimized.

vovkab commented Jan 8, 2016

Still reproduceable in 2.7.2:

compile 'com.squareup.okhttp:okhttp:2.7.2'
compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.2'
compile 'com.squareup.retrofit:retrofit:1.9.0'
Caused by: java.lang.IllegalArgumentException: method POST must have a request body.
  at com.squareup.okhttp.Request$Builder.method(Request.java:259)
  at retrofit.client.OkClient.createRequest(OkClient.java:59)
  at retrofit.client.OkClient.execute(OkClient.java:53)
  at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:342)
  at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:251) 
@calren

This comment has been minimized.

calren commented Jan 14, 2016

also seeing this issue in 2.7.2

@pgreze

This comment has been minimized.

pgreze commented Jan 15, 2016

I don't understand: this bug is very old, seems closed but still in the latest version.

This problem has broken many libraries (like twitter-core) and many developers are probably stuck with an old version.

Could you reopen the issue or explain this breaking change in public API?

(Thanks for your answer and this wonderful library 😄 )

@WonderCsabo

This comment has been minimized.

WonderCsabo commented Jan 15, 2016

@pgreze this is already fixed in the latest version.

@pgreze

This comment has been minimized.

pgreze commented Jan 15, 2016

@WonderCsabo Nice! But what about 1.x releases?
Because I can't tell you when my app (or twitter-core) will migrate to retrofit2.

@WonderCsabo

This comment has been minimized.

WonderCsabo commented Jan 15, 2016

Well that fix was added before changing the version to 2.x, so it is possible, but only @JakeWharton and @swankjesse can know they want to release an update for 1.x or not . :)

@doc-rj doc-rj referenced this issue Jan 16, 2016

Closed

retrofit lib issue #8

@efrohnhoefer

This comment has been minimized.

efrohnhoefer commented Feb 4, 2016

Looks like version 1.9.0 was released Jan 7th. However, 19ac1 was merged June 2nd. The fix never made it into a 1.x release.

wmfgerrit pushed a commit to wikimedia/apps-android-wikipedia that referenced this issue Feb 19, 2016

Work around empty Retrofit POST request bodies
square/retrofit#854 (comment)

Change-Id: I738c1d739e8bc871e4392b64050e7083ab72c40f
@xiaolongyuan

This comment has been minimized.

xiaolongyuan commented Apr 29, 2016

+1

@pixoo

This comment has been minimized.

pixoo commented Jul 7, 2016

@Body String emptyBody wasn't working for me as backend server I was working with, was returning Bad request and not accepting empty string as a body.

I've just sent empty JSON instead of empty String

@POST("/some/url) Observable<Thing> doThing(@Body JsonElement empty);

and then I just called my method like this:

doThing(new JsonObject());

Hope it will help if some of users have similar problem.

@aitbaali

This comment has been minimized.

aitbaali commented Aug 14, 2016

compile 'com.squareup.okhttp:okhttp:2.3.0'works for me

@Isanderthul

This comment has been minimized.

Isanderthul commented Feb 26, 2017

@pixoo I did as you suggested, thank you, it was the easiest solution. Just a note that on using JsonObject, but I needed to use @Body JsonObject empty

 @POST("reports/{report_id}")
   Call<APISuccess> resendUserReportById(@Path("report_id") String var1, @Body JSONObject empty);

and then
Call<APISuccess> request = reportsApi.resendUserReportById(intentReportId,new JSONObject());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment