Retrofit路径替换:替换整个路径(包括 /)

30

在我的设置中,我从对REST API的初始调用中获取所有资源路径。 我们使用这种模式,以便能够更改所有资源路径而不会破坏现有应用程序版本。

我一直在尝试使用Retrofit并尝试创建一个可以接受我传递的任何路径的字符串的方法。 我的尝试看起来像这样

@GET("/{path}")
public FooBar getFooBar(@Path("path") String path);

我接着尝试按以下方式调用它。

String path = "foo/bar";
api.getFooBar(path);

不幸的是,Retrofit会对路径替换进行URL编码,导致我最终向/foo%2Fbar发出请求,而不是/foo/bar。是否有办法禁用路径替换的URL编码或使替换跨越多个路径段?不幸的是,我甚至不知道有多少路径段,这全部由API控制。

5个回答

45
使用@EncodedPath!就这样。我将复制Javadoc,以便此答案更加详细:

在URL路径中命名替换。使用String.valueOf(Object)将值转换为字符串。 值是按字面意义使用,而不进行URL编码。 有关URL编码等效的信息,请参见@Path

像这样使用它:
@GET("/{path}")
void example(@EncodedPath("path") String path, ..);

1
我现在无法尝试,但既然它如此明显,我会相信你并接受答案。非常感谢! :-) - Thrakbad
1
我认为@EncodedPath现在已经被弃用了。 - Martin Marconcini
5
可以。从1.7.0版本开始,您可以使用@Path及其标志之一。 - Jake Wharton
13
@GET("/user/{name}") void notEncoded(@Path(value="name", encode=false) String name);这段代码的意思是发送一个 HTTP GET 请求到以"/user/"开头、后面跟着一个变量名为"name"的路径,其中变量值不进行 URL 编码。在该请求中,将使用给定的name参数作为路径中"name"变量的值。 - Code_Life
2
以上解决方案均不适用于Retrofit 2.0。我在https://github.com/square/retrofit/issues/1364上创建了一个问题。 - Iwo Banas
6
请使用@Code_Life的解决方案,因为@EncodedPath已被弃用。使用@Path(value = "link", encode = false) String link - alxsimo

24

由于@EncodedPath现在已被弃用

Retrofit 1.9:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);

Retrofit 2.*:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);

6
它对我起作用了,但我在Retrofit 2.3中将encoded=true进行了更改。 - Lokesh
2
编码的标志实际上意味着:true - 我自己进行了编码,非常感谢。false - 请为我进行编码。这种说法相当模糊! - Ahmed Awad
即使在我的测试中将encoded = true,Retrofit仍然会对URL进行编码。 - Rod

12

现有已知的bug,您可以在以下链接中查看bug报告: Retrofit @Github

此外,这里还有一个可能的解决方案链接:Solution @Github

最后,Retrofit开发人员的消息是:

"不支持跨越多个路径段的路径替换,如果路径段数量动态变化,应该使用@Url来以程序方式构建完整的相对URL。"

所以,如果您在编码方面遇到麻烦,解决方案可能是:

您的GET API:

@GET
Call<Object> Function(@Url String path, @Query("CONTENT") String content);

您的POST API:

@FormUrlEncoded
@POST
Call<Object> Function(@Url String path, @Field("CONTENT") String content);

你可以使用以下代码进行调用:

String thePath = "www.foo.de/foo/foo2";
Call<Object> call = api.Function(thePath,content);

因此,使用此方法,您不必担心编码问题。

但是,如果您只是想要版本2.*中的普通编码,则API应该如下所示:

@GET("/{path}")
void example(@Path(value = "path", encoded = false) String path, ..);

敬礼


3
是的,他们在2.0.0版本中将“encode”更改为“encoded”。 - Thrakbad

4

已经测试并且现在正常工作。解决方案就是添加encoded = true以确保访问正确的URL。 例如:

@POST("{attendance_path}")
Single<Response> upLoadAttendence (@PartMap HashMap<String, RequestBody> postData,@Path(value = "attendance_path",encoded = true) String path);

当您在字符串路径中包含符号?时,这将无法正常工作。 - Panos Gr

0

我遇到了同样的问题,并通过以下代码解决了它

 @POST(ApiKey.URL.add_edit_notice + "{id}")
    @FormUrlEncoded
    Call<GenericResponse> callAddNotice(@Path(value = "id", encoded = true)  String id,
                                        @Field("user_id") String user_id,
                                        @Field("title") String title,
                                        @Field("description") String description,
                                        @Field("school_id") String school_id,
                                        @Field("filename") String filename);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接