Using nanohttpd for server on localhost, how to serve the static HTML code in the whole directory?

lka*_*htz 5 html java android localhost nanohttpd

I can't make nanohttpd work. It seems not be able to find the www directory in app's root.

My code is at https://github.com/tlkahn/neonx

My code at MainActivity.java:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        mWebView = findViewById(R.id.webkit);
        navView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        webSettings.setDomStorageEnabled(true);
        mWebView.getSettings().setLoadsImagesAutomatically(true);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                return false;
            }
        });
        if (!haveNetworkConnection()) {
            new AlertDialog.Builder(this)
                .setTitle("You are not connected to internet.")
                .setMessage("Are you sure you want to exit?")
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finishAffinity();
                        System.exit(0);
                    }
                }).setNegativeButton("No", null).show();
        }
        startLocalServer(3000, "www", true, true );
    }

  public void startLocalServer(int port, String root, Boolean localhost, Boolean keepAlive) {
      try {
          File www_root = new File(root);
          server = new WebServer("localhost", port, www_root.getAbsoluteFile());
          server.start();
          printIp();
      } catch (IOException e) {
          e.printStackTrace();
      }
  }
Run Code Online (Sandbox Code Playgroud)

When I tried to visit localhost:3000, I got the error: given path is not a directory. The error seems to come from this line: https://git.io/fjS3f

I guess the way I initialize the rootDir is wrong (this line: https://git.io/fjS3v). But how can I make this work? I mean to serve the whole directory, which means all CSS/JS/hypyerlinks should work, once nanohttpd starts serving...

Yur*_*kov 6

问题是您无法像访问本地文件一样访问资产文件夹中的文件。您必须扩展 NanoHTTPD 并覆盖 serve(IHTTPSession) 才能提供资产。这是 Kotlin 中的一个例子。如果您无法阅读它,请告诉我,我会将其移植到 Java。

class FileServer(private val context: Context, port: Int) : NanoHTTPD(port) {
override fun serve(session: IHTTPSession): Response {
    val uri = session.uri.removePrefix("/").ifEmpty { "index.html" }
    println("Loading $uri")
    try {
        val mime = when (uri.substringAfterLast(".")) {
            "ico" -> "image/x-icon"
            "css" -> "text/css"
            "htm" -> "text/html"
            "html" -> "text/html"
            else -> "application/javascript"
        }

        return NanoHTTPD.newChunkedResponse(
            Response.Status.OK,
            mime,
            context.assets.open("www/$uri") // prefix with www because your files are not in the root folder in assets
        )
    } catch (e: Exception) {
        val message = "Failed to load asset $uri because $e"
        println(message)
        e.printStackTrace()
        return NanoHTTPD.newFixedLengthResponse(message)
    }
}
Run Code Online (Sandbox Code Playgroud)


Sah*_*nda 5

输出: 在此处输入图片说明

LogCat:

2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: -------Assets List-----
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: asset-manifest.json
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: favicon.ico
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: index.html
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: manifest.json
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: precache-manifest.81af63d07b6dd6ae8e331187c522b020.js
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: service-worker.js
2019-08-05 15:21:53.838 10650-10650/com.neonxorg.neonx E/MainActivity: static
2019-08-05 15:21:53.842 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www
2019-08-05 15:21:53.865 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static
2019-08-05 15:21:53.867 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/css targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/css
2019-08-05 15:21:53.922 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/js targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/js
2019-08-05 15:21:54.352 10650-10650/com.neonxorg.neonx E/MainActivity: copyFolderFromAssets rootDirFullPath-www/static/media targetDirFullPath-/storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static/media
2019-08-05 15:21:54.526 10650-10650/com.neonxorg.neonx E/MainActivity: -------Root File List-----
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/precache-manifest.81af63d07b6dd6ae8e331187c522b020.js
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/service-worker.js
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/static
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/favicon.ico
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/manifest.json
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/asset-manifest.json
2019-08-05 15:21:54.528 10650-10650/com.neonxorg.neonx E/File: /storage/emulated/0/Android/data/com.neonxorg.neonx/cache/www/index.html
2019-08-05 15:21:54.704 10650-10650/com.neonxorg.neonx E/MainActivity: Connected : Please access! http://192.168.1.2:3000 From a web browser
Run Code Online (Sandbox Code Playgroud)

码:

public final String TAG = getClass().getSimpleName();
public void startLocalServer(int port, String root, Boolean localhost, Boolean keepAlive) {
        try {
            String[] filePathList = (getAssets().list("www"));
            Log.e(TAG,"-------Assets List-----");
            for (String s : filePathList) {
                Log.e(TAG, s);
            }
            File externalCache = getExternalCacheDir();
            if (externalCache != null) {
                String path = externalCache.getAbsolutePath() + "/" + root;
                copyFolderFromAssets(getApplicationContext(), "www", path);
                File www_root = new File(path);
                Log.e(TAG,"-------Root File List-----");
                for (File f : www_root.listFiles()) {
                    Log.e("File ", f.getAbsolutePath());
                }
                server = new WebServer("localhost", port, www_root.getCanonicalFile());
                server.start();
                printIp();
            }

        } catch (IOException e) {
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

    public void copyFolderFromAssets(Context context, String rootDirFullPath, String targetDirFullPath) {
        Log.e(TAG,"copyFolderFromAssets " + "rootDirFullPath-" + rootDirFullPath + " targetDirFullPath-" + targetDirFullPath);
        File file = new File(targetDirFullPath);
        if (!file.exists()) {
            new File(targetDirFullPath).mkdirs();
        }
        try {
            String[] listFiles = context.getAssets().list(rootDirFullPath);// ?????????????
            for (String string : listFiles) {// ???????????????????.????
                if (isFileByName(string)) {// ??
                    copyFileFromAssets(context, rootDirFullPath + "/" + string, targetDirFullPath + "/" + string);
                } else {// ???
                    String childRootDirFullPath = rootDirFullPath + "/" + string;
                    String childTargetDirFullPath = targetDirFullPath + "/" + string;
                    new File(childTargetDirFullPath).mkdirs();
                    copyFolderFromAssets(context, childRootDirFullPath, childTargetDirFullPath);
                }
            }
        } catch (IOException e) {
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }


    public void copyFileFromAssets(Context context, String assetsFilePath, String targetFileFullPath) {
        InputStream assestsFileInputStream;
        try {
            assestsFileInputStream = context.getAssets().open(assetsFilePath);
            FileOutputStream fOS = new FileOutputStream(new File(targetFileFullPath));
            int length = -1;
            byte[] buf = new byte[1024];
            while ((length = assestsFileInputStream.read(buf)) != -1) {
                fOS.write(buf, 0, length);
            }
            fOS.flush();
        } catch (IOException e) {
            Log.e(TAG, Log.getStackTraceString(e));
        }
    }

    private boolean isFileByName(String str) {
        return str.contains(".");
    }

    private void printIp() {
        WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
        int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
        final String formatedIpAddress = String.format("%d.%d.%d.%d", (ipAddress & 0xff), (ipAddress >> 8 & 0xff),
                (ipAddress >> 16 & 0xff), (ipAddress >> 24 & 0xff));
        Log.e(TAG,"Connected : " + "Please access! http://" + formatedIpAddress + ":" + server.getListeningPort() + " From a web browser");
    }
Run Code Online (Sandbox Code Playgroud)

给定的路径不是目录。

当nanphttpd无法找到数据时,则会出现此错误。

为什么您没有得到实际的错误

copyFolderFromAssetscopyFileFromAssets您正在使用的catch块中,e.printStackTrace()由于仅显示选定的应用程序筛选器而可能未显示在LogCat

在此处输入图片说明

为了打印错误,您需要使用以下内容:

Log.e(TAG, Log.getStackTraceString(e));
Run Code Online (Sandbox Code Playgroud)

我用Log.e语句替换了所有的System.out和e.printStackTrace。该应用很可能无法将内容从www目录复制到目标目录。我将目标目录更改为缓存目录,并且它可以在我的设备上使用。(见下文):

File externalCache = getExternalCacheDir();
if (externalCache != null) {
    String path = externalCache.getAbsolutePath() + "/" + root;
    File www_root = new File(path);
    copyFolderFromAssets(getApplicationContext(), "www", path);
    Log.e(TAG,"-------Root File List-----");
    for (File f : www_root.listFiles()) {
        Log.e("File ", f.getAbsolutePath());
    }
    server = new WebServer("localhost", port, www_root.getCanonicalFile());
    server.start();
    printIp();
}
Run Code Online (Sandbox Code Playgroud)

边注:

  • static直到或除非您要将它们复制到实用程序类中,才需要在那些函数中使用关键字