Android上NanoHTTPD的意外HTTP 400状态代码

时间:2015-10-01 18:53:23

标签: android nanohttpd

朋友!

我在Android应用中收到来自nanohttpd的偶然和意外的HTTP 400响应。错误遵循特定模式。我已经看了一段时间了,但是我已经到了需要不同角度或其他帮助指向正确方向的地方。

您能否请一看,分享您的想法,甚至直接提出意见和建议?

  • 为什么我会收到此HTTP 400状态代码?
  • 为什么只有在特定情况下呢? (我根本不想要它!)

一些背景

我在我的Android项目中运行nanohttpd作为临时隔离层(由于服务器端还不够成熟)。我已将Android nanohttpd中的Service服务器隔离开来,一旦创建,我就从我的自定义Application对象开始。这种方式nanohttpd不受任何特定Activity生命周期的约束,但可以独立于整个应用程序逻辑和组件生命周期而生存。

问题

现在,(差不多)一切都运行良好和花花公子:我可以启动nanohttpd并执行一些初始登录请求,我的预期模拟响应甚至可以传递。但是,当我执行第一次“GET”请求时,nanohttpd会向我发送400 Bad请求状态,但仅限第一次。如果我退出负责特定“GET”请求的Activity,并再次启动它(从主屏幕),它会以200状态完美地传递预期的有效负载。

我做了什么

我仔细查看了nanohttpd源代码,试图找出设置此400状态的位置和原因。使用此状态代码并不是很多地方。粗略地说只有hereherehere。由于我没有处理多部分内容,我留下了第一个和第三个“这里”。但是 - 当然 - 我不能为我的生活找到400状态的根本原因,也不会找到导致我状态的确切块。当我调试代码时,一切都很好用。

部分代码

这大致是我的nanohttpd ServiceMyNanoHttpdService)的样子:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (ACTION_START.equals(intent.getAction())) {
        String errorMessage = null;

        if (myNanoHttpd == null) {
            String hostUrl = intent.getStringExtra(EXTRA_HOST);
            Uri uri = Utils.notEmpty(hostUrl) ? Uri.parse(hostUrl) : Uri.EMPTY;
            myNanoHttpd = new MyNanoHttpd(this, uri.getHost(), uri.getPort(), null);
        }

        if (!myNanoHttpd.isAlive()) {
            try {
                myNanoHttpd.start();
            } catch (IOException e) {
                StringWriter stringWriter = new StringWriter();
                PrintWriter printWriter = new PrintWriter(stringWriter);
                e.printStackTrace(printWriter);
                errorMessage = stringWriter.toString();
                stopSelf();
            }
        }

        final ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_RESULT_LISTENER);
        if (resultReceiver != null) {
            int status = myNanoHttpd.isAlive() ? CODE_SUCCESS : CODE_FAILURE;
            Bundle bundle = new Bundle();
            bundle.putString(EXTRA_MESSAGE, errorMessage);
            resultReceiver.send(status, bundle);
        }
    }

    return Service.START_STICKY;
}

这就是我从自定义Application对象启动服务的方式,初始化我的客户端状态并获取一些内容:

@Override
public void onCreate() {
    super.onCreate();

    // Yes, that is a Java 8 Lambda you see there!
    MyNanoHttpdService
            .start(this, "http://localhost:8080")
            .withStartupListener((status, message) -> {
                if (status == 0) {
                    // POST REQUEST: Works like a charm
                    myNetworkHelper.login();

                    // GET REQUEST: Always fails on first launch
                    myNetworkHelper.getContent();
                } else {
                    Log.e("LOG_TAG", "Couldn't start MyNanoHttpd: " + message);
                }
            });
}

可以安全地假设包装便利代码(.withStartupListener(...) - 基本上包含了上述ResultReceiver使用的Service - 和myNetworkHelper对象)预期。此外,在制作中,getContent()来自ActivityFragment,但为了方便起见,我暂时将其移至Application

1 个答案:

答案 0 :(得分:1)

我可能已找到问题的根本原因,甚至可能是目前的解决方法。

如果我的调查结果正确,则问题是由先前(POST)请求中的未使用数据引起的,从而污染了当前(POST)请求。

NanoHTTPD代码库中的

This行(NanoHTTPD.HTTPSession.execute()方法中的标题解析块,在调用任何自定义serve(...)方法之前 - 第三个&# 34;这里"在上面的问题中)是抛出HTTP 400状态代码的那一行,正如代码所示,"method"标题没有正确的值。

价值 - 我期望的是" POST"以明文形式 - 被上一个请求中的JSON内容正文部分污染。一旦我意识到这一点,我就尝试使用自定义MyNanoHttpd.serve(IHTTPSession session)方法使用整个请求正文,如下所示:

@Override
public Response serve(IHTTPSesion session) {
    InputStream inputStream = session.getInputStream();
    inputStream.skip(inputStream.available());

    // or
    // inputStream.skip(Long.MAX_VALUE);

    // or even
    // inputStream.close();

    ...

}
但是,这并没有奏效,因为我不断得到各种例外。我最后轻轻地修改了NanoHTTPD代码,安全地关闭了finally方法的NanoHTTPD.HTTPSession.execute()块中的输入流。

尽管如此,我还是考虑与NanoHTTPD社区联系,讨论合适且可持续的解决方案。