朋友们!

我的Android应用程序中的nanohttpd偶尔会收到意外的HTTP 400响应。错误遵循特定的模式。我已经看了一段时间了,但是到了我需要改变角度或其他一些帮助我指出正确方向的地步。

您可以看看并分享您的想法,甚至直接的观点和建议吗?


为什么会收到此HTTP 400状态代码?
为什么只在给定的情况下? (我一点都不想要!)


一些背景

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

问题

现在,(几乎)一切工作都很好,很好:我可以启动nanohttpd并执行一些初始登录请求,甚至可以传递预期的模拟响应。但是,当我执行第一个“ GET”请求时,nanohttpd向我抛出400错误的请求状态,但这只是第一次。如果我退出Activity负责特定的“ GET”请求,并再次启动它(从主屏幕),它会以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

最佳答案

我可能已经找到问题的根本原因,甚至可能暂时也无法解决。

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

NanoHTTPD代码库中的This行(在调用任何自定义NanoHTTPD.HTTPSession.execute()方法之前,在serve(...)方法中的标头解析块-上面我的问题中的第三个“ here”)就是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社区联系,讨论合适的可持续解决方案。

关于android - Android上来自NanoHTTPD的意外HTTP 400状态代码,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32894816/

10-10 13:34