在NanoHTTPD中检索HTTP正文

24
我该如何在实现NanoHTTPDserve方法时检索HTTP POST请求正文?
我已经尝试使用IHTTPSessiongetInputStream()方法,但是当我在serve方法内部使用它时,总是会得到一个SocketTimeoutException

1
如何使用GET方法从URL获取参数? - Ray
5个回答

33
serve方法中,您首先需要调用session.parseBody(files),其中files是一个Map<String, String>,然后session.getQueryParameterString()将返回POST请求的主体内容。
我在源代码中找到了示例,以下是相关代码:
public Response serve(IHTTPSession session) {
    Map<String, String> files = new HashMap<String, String>();
    Method method = session.getMethod();
    if (Method.PUT.equals(method) || Method.POST.equals(method)) {
        try {
            session.parseBody(files);
        } catch (IOException ioe) {
            return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
        } catch (ResponseException re) {
            return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
        }
    }
    // get the POST body
    String postBody = session.getQueryParameterString();
    // or you can access the POST request's parameters
    String postParameter = session.getParms().get("parameter");

    return new Response(postBody); // Or postParameter.
}

1
有没有任何理由需要在调用 session.getQueryParameterString() 之前先调用 session.parseBody(files) - vatsa
4
我查看了源代码:当处理非 multipart/form-data 请求时,session.parseBody(files) 会读取 POST 请求的正文,并调用 HTTPSession 的 decodeParms() 方法 (https://github.com/NanoHttpd/nanohttpd/blob/852318439539b54ee6b4ce048df63b6c12cf0417/core/src/main/java/fi/iki/elonen/NanoHTTPD.java#L1005),该方法将 queryParameterString 和 parms 字段值设置为 POST 请求的正文。如果没有调用 session.parseBody(),这些字段就是空的。 - bob esponja

32

IHTTPSession实例上,您可以调用.parseBody(Map<String, String>)方法,它将使用一些值填充您提供的映射。

之后,您的映射可能包含一个键为postBody的值。

        final HashMap<String, String> map = new HashMap<String, String>();
        session.parseBody(map);
        final String json = map.get("postData");

这个值将保存你的帖子正文。

实现此功能的代码可以在此处找到。


2
迄今为止最好的解决方案,特别是在使用JSON时。 - Abid H. Mujtaba
2
请注意,如果Content-Type为application/x-www-form-urlencoded,则参数的内容将在session.getParms()下找到,而不是您提供的map对象。 - Aditya Santoso
3
еҪ“content-typeдёәapplication/jsonж—¶пјҢеҜ№жҲ‘жңүж•Ҳзҡ„е”ҜдёҖи§ЈеҶіж–№жЎҲгҖӮ - Sudara
1
@Rinmalavi谢谢您发布代码链接,其中清晰地显示了files.put("postData", postLine);。一个需要使用postData才能获取数据...但是否有任何以文档形式的链接? - CrandellWS
2
@CrandellWS 根据我在2014年使用它的记忆,文档大部分是代码本身。不确定现在是否有所改变。抱歉没有答案。 - Rin malavi
你如何模拟 sesssion.parseBody(map)? - Nikhil Lingam

12

我认为在这种情况下session.getQueryParameterString();不起作用。

如果您使用POSTPUT,您应该尝试以下代码:

Integer contentLength = Integer.parseInt(session.getHeaders().get("content-length"));
byte[] buffer = new byte[contentLength];
session.getInputStream().read(buffer, 0, contentLength);
Log.d("RequestBody: " + new String(buffer));

事实上,我尝试了IOUtils.toString(inputstream, encoding),但它导致了Timeout异常


session.getHeaders().get("content-length") == null? - Hooli
当提交的数据不是纯字符串格式时,这种方法比其他方法更好。 - yorkw

0
这是我使用NanoHttp获取我的帖子响应正文的方式,对我很有效。非常重要的是,请注意,如果您正在处理自己的错误响应代码并想要发送正文,请使用错误输入流而不是conn.getInputStream()。这将避免在服务器发送正文之前关闭连接时出现文件未找到异常或断开的管道异常。
 public HashMap<String, Object> getResponse(HttpURLConnection conn) throws IOException {

        Log.i("STATUS", String.valueOf(conn.getResponseCode()));
        Log.i("MSG", conn.getResponseMessage());

        StringBuilder response = new StringBuilder();

        String line;
        BufferedReader br;

        if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK)
             br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

        else
            br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));

        while ((line = br.readLine()) != null)
            response.append(line);

        conn.disconnect();
        return new Gson().fromJson(response.toString(), HashMap.class);

0

我使用过这种方法,在没有套接字异常的情况下适用于我。

String body = "";

try {
    Map<String, String> headers = session.getHeaders();
    if (headers == null || headers.get("content-length") == null) {
        iDoMethodInThread.onException(new Exception("No Content length found in header"));
        return;
    }
    int contentLength = Integer.parseInt(headers.get("content-length"));
    byte[] buffer = new byte[contentLength];
    int totalRead = 0;
    while (totalRead < contentLength) {
        int read = session.getInputStream().read(buffer, totalRead, contentLength - totalRead);
        if (read == -1) {
            break;
        }
        totalRead += read;
    }
    body = new String(buffer, StandardCharsets.UTF_8);
} catch (IOException e) {
    e.printStackTrace();
}

您的答案可以通过提供更多支持性信息来改进。请进行[编辑]以添加更多细节,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何编写好答案的更多信息。 - Community

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