朋友们!
我的Android应用程序中的nanohttpd
偶尔会收到意外的HTTP 400响应。错误遵循特定的模式。我已经看了一段时间了,但是到了我需要改变角度或其他一些帮助我指出正确方向的地步。
您可以看看并分享您的想法,甚至直接的观点和建议吗?
为什么会收到此HTTP 400状态代码?
为什么只在给定的情况下? (我一点都不想要!)
一些背景
我正在Android项目中将nanohttpd
作为临时隔离层运行(由于服务器端还不够成熟)。我在Android nanohttpd
中隔离了Service
服务器,该服务器从创建自定义Application
对象开始。这种方式nanohttpd
不受任何特定Activity
生命周期的束缚,而是可以独立于整体应用程序逻辑和组件生命周期而生存。
问题
现在,(几乎)一切工作都很好,很好:我可以启动nanohttpd
并执行一些初始登录请求,甚至可以传递预期的模拟响应。但是,当我执行第一个“ GET”请求时,nanohttpd
向我抛出400错误的请求状态,但这只是第一次。如果我退出Activity
负责特定的“ GET”请求,并再次启动它(从主屏幕),它会以200状态完美地提供预期的有效负载。
到目前为止我做了什么
我仔细查看了nanohttpd
源代码,试图找出设置此400状态的位置和原因。使用此状态代码的地方并不多。大致而言,仅here,here和here。由于我不处理多部分内容,因此只剩下第一个和第三个“这里”。但是-当然-我一生都找不到400状态的根本原因,也没有找到导致我状态的确切障碍。当我调试代码时,一切正常。
一些代码
这大致就是我的nanohttpd
Service
(MyNanoHttpdService
)的样子:
@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()
调用将由Activity
或Fragment
进行,但是为了简便起见,我现在将其移至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/