【问题标题】:UrlEncodedFormEntity doesn't encode underscoreUrlEncodedFormEntity 不编码下划线
【发布时间】:2014-02-10 01:11:21
【问题描述】:

我想在我的 Android 设备上使用远程 API,但由于某种原因,UrlEncodedFormEntity 类不会像远程 API 预期的那样将 _ 转换为 %5f。因此,使用此代码:

List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(
    new BasicNameValuePair("json", 
        "{\"params\":{\"player_name\":\"Toto\",
            \"password\":\"clearPass\"},
            \"class_name\":\"ApiMasterAuthentication\",
            \"method_name\":\"login\"}")
    );
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
ResponseHandler responseHandler = new BasicResponseHandler();
httpClient.execute(httpPost, responseHandler);

向服务器发送一个发布请求,内容如下:

json=%7B%22params%22%3A%7B%22player_name%22%3A%22Toto%22%2C%22password%22%3A%22clearPass%22%7D%2C%22class_name%22%3A%22ApiMasterAuthentication%22%2C%22method_name%22%3A%22login%22%7D

我希望它是这样的(将之前的下划线替换为 %5F):

json=%7B%22params%22%3A%7B%22player%5Fname%22%3A%22Toto%22%2C%22password%22%3A%22clearPass%22%7D%2C%22class%5Fname%22%3A%22ApiMasterAuthentication%22%2C%22method%5Fname%22%3A%22login%22%7D

我无法控制 API,API 的官方客户端行为是这样的。这似乎是 URL normalization 的预期行为

我错过了什么吗?我一开始以为是UTF-8编码问题,但是在UrlEncodedFormEntity的构造函数中添加HTTP.UTF-8并不能解决问题。

感谢您的帮助。

编辑:最后,问题不是来自这个不转义的下划线。即使我试图重现该行为的其他客户端逃脱了它,我也只需要设置正确的标题:

httpPost.addHeader("Content-Type","application/x-www-form-urlencoded");

请求工作得很好。感谢大家,尤其是 singh.jagmohan 的帮助(即使问题最终出在其他地方)!

【问题讨论】:

    标签: java android http url apache-httpclient-4.x


    【解决方案1】:

    “_”不是 url 的保留符号。

    设置:Content-Type: application/x-www-form-urlencoded'

    应该可以解决问题。否则,如果你真的需要这个选项,你可以尝试替换它:

    String.Replace("_", "%5f");
    

    percent encodeing,replace

    【讨论】:

    • 您的解决方案不起作用,因为当我将 _ 替换为 %5F 时,% 符号就是转码为 %25。结果,player_name 变为 player%255Fname 而不是 player%5Fname
    • 好吧,终于不用换了,你是对的。唯一的问题是设置正确的标题Content-Type: application/x-www-form-urlencoded 你说它不应该被替换的事实让我阅读了更多关于 url 转义的文档并寻找另一个错误来源。感谢您的帮助。
    • 我将添加解决方案以供将来参考。很高兴它有帮助。
    【解决方案2】:

    你可以试试下面的代码,它对我有用。

    try {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(serviceUrl);
        MultipartEntity multipartEntity = new MultipartEntity();
        // Also, in place of building JSON string as below, you can build a **JSONObject**
        // and then use jsonObject.toString() while building the **StringBody** object
        String requestJsonStr = "{\"params\":{\"player_name\":\"Toto\",\"password\":\"clearPass\"},\"class_name\":\"ApiMasterAuthentication\",\"method_name\":\"login\"}";
        multipartEntity.addPart("json", new StringBody(requestJsonStr));
        httpPost.setEntity(multipartEntity);
        HttpResponse response = httpClient.execute(httpPost);
    } catch (Exception ex) {
        // add specific exception catch block above
        // I have used this one just for code snippet
    }
    

    PS:代码sn-p需要两个jar文件apache-mime4j-0.6.jarhttpmime-4.0.1.jar .

    希望这会有所帮助。

    【讨论】:

    • MultipartEntity 似乎不存在于 Android SDK 中嵌入的 HttpClient 版本中。您是否尝试过 Android 项目或 Java 项目?
    • 这需要 JAR 文件,apache-mime4j-0.6.jar 和 httpmime-4.0.1.jar。很抱歉忘记提及这一点,我也会更新我的答案。
    • 即使有这个库,我仍然有同样的问题:当我分析在我的代理上发送的数据包时,下划线仍然存在(而另一个客户端在我的代理上发送了编码的下划线)。问题可能来自其他地方吗? (我将您的代码示例从 Linux 上的 Android Studio 运行到我的 Android Nexus 5 手机)
    • 不,我不这么认为。我想知道的是你怎么能说它对你有用?您使用了代理还是网络嗅探器?如果此代码对您有用(它将“_”转换为“%5F”,这意味着问题出在其他地方。
    • 实际上,我的服务器接受 JSON 对象,我认为将其作为 multipart/form-data 的一部分上传也可能对您的情况有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-12
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2011-05-06
    • 2011-01-14
    • 1970-01-01
    相关资源
    最近更新 更多