问题
在进行一个http的post请求时,使用Retrofit+okhttp3发起网络请求,但是这个post请求有点特殊,因为在请求头上要带个参数,而且参数里面还有【/】,刚开始没重视,然后就按照平时的请求方式进行实现,但是出现问题了,因为参数传的是错误的。在使用get请求获取到传入的参数的后,发现我本来传入的是一个【/】,但是获取到的参数是【//】,例如我传入的参数为【data/user】,返回的是【data//user】。
我:
问题分析
这是因为在 HTTP URL 中,斜杠 (/) 被视为分隔符,用于分隔 URL 的各个部分。在 URL中,每个斜杠字符都表示一个新的路径段。当将包含单个斜杠字符的路径作为 URL 参数传递时,它会被视为新的路径段,并且由于URL编码的原因,每个斜杠字符都会被编码为 %2F,因此单个斜杠字符会被编码为%2F%2F。当在多个路径段中传递多个斜杠字符时,它们也会被编码为多个 %2F,从而导致在查询时看到多个斜杠字符。
问题解决
为了避免这种情况,可以在将路径作为 URL 参数传递之前,对其进行 URL 编码。在Java 中,可以使用 URLEncoder.encode()方法来对路径进行 URL编码。这将会将斜字符和其他特殊字符编码为它们的 URL 编码形式,从而避免它们被解释为 URL 的分隔符.在收到编码后的路径时,可以使用 URLDecoder.decode() 方法对其进行解码。这将会还原路径中的所有特殊字符,包括斜杠字符
其中这个 URLEncoder.encode()的使用
这个一个参数的方法已经被废弃了,可以使用两个参数的方法。
//第二个参数可以传入UTF-8或者GBK等一种编码方式
val valueEncoder = URLEncoder.encode("传入的需要转义的参数", "UTF-8")
但是当我在Retrofit中使用这个时,并没有获得预期的效果,最后还是传入错误的参数,没办法,打印了上传的URL地址,发现当我没有使用【 URLEncoder.encode()】方法的时候,Retrofit里面已经将【/】转义为了【%2F】,相当于Retrofit已经自动帮我实现了【/】的转义,而我在使用这个方法后,又转义了一次,将【%2F】转义成了【%252F】,相当于转义了两次。
最终解决方式
因为Retrofit会自动帮我们进行字符串的转义,但是我这次的http请求是不需要进行转义的,因为没有对应的【URLDecoder.decode() 】进行解码,所以我们不能再让Retrofit帮我们进行组装URL地址了,需要我们自己确定一个URL,然后我使用【@URL】注解来解决这个问题
@POST()
suspend fun postLamp2(@Url url: String): ResponseBody
然后我们自己组装一个URL使用
"http://${lampIP}/cgi-bin/Config.cgi?action=set&property=${property}&value=${value}"
这样就不会有转义的出现了。
注意
使用此方式的时候,虽然我们不需要再使用Retrofit的BASE_URL
private const val BASE_URL = "http://"
但是这个【BASE_URL 】也还是要加上的,而且这个【“http://”】后面也是要有东西的,像上面这个是要报错的,我们可以随便加点什么。
这里我加上了这些东西,但是没什么用,因为我们并不会用到
.baseUrl(BASE_URL + "cgi-bin/")