Nginx list static files/directories as XML/Json

2019-05-17 23:53发布

问题:

I installed nginx with the intent of serving static files like photos and videos, being able to programmatically list the files served.

The problem is that this listing is done in a HTML page and for my application I needed to be able to process this listing (something like json or xml).

Is there anyway I can do this with nginx? (Or are there any other alternatives which solve my problem)

Thanks in advance.

回答1:

Since version 1.7.9 you can use autoindex_format set to json or xml, refer to the docs here.

location / {
    ...
    autoindex on;
    autoindex_format json;
}


回答2:

The ngx_http_autoindex_module Module (which produces a directory listing for requests ending with the slash character: /) included in NGINX since version 1.7.9 (released 2014-12-23) added an autoindex_format directive that sets the format of a directory listing:

Syntax: autoindex_formathtml | xml | json | jsonp;
Default: autoindex_format html;
Context: http, server, location

Example config to enable this feature (for JSON):

location / {
    autoindex on;
    autoindex_format json;
}

When the JSONP format is used then the name of a callback function is set with the callback request argument. If that argument is missing or has an empty value, then the JSON format is returned.

The JSON(P) response data structure (scheme) is defined as :

callback(  // when format directive jsonp AND callback argument in request
  [ // a single one-dimensional Array (wrap) containing
    { // Objects representing directory entries, structured as:
      "name" :"*"                             //String
    , "type" :"directory"|"file"|"other"      //String, ONLY 1 OF THESE 3
    , "mtime":"Ddd, DD Mmm YYYY hh:mm:ss GMT" //String, RFC1123-date of HTTP-date defined by RFC2616
    , "size" :*   //Integer,  ONLY PRESENT IFF "type":"file" !!!!! 
    } /*
  , { // and repeating the above Object structure for each directory entry
    } */
  ]
); // end callbackFunction-call when jsonp

The "name", "mtime", "type":"directory" and "type":"file" should be pretty self-explanatory.
Important to note that the "size" field is ONLY present IFF "type":"file", otherwise it is omitted entirely (see examples below) !!

"type":"other" deserves some further explanation:
Suppose you did something you'd never do in production and set 'root /;' in the config on a linux system and subsequently index /dev/ then you'd get directory-entries like:

[
{ "name":"floppy", "type":"other", "mtime":"Mon, 23 Oct 2017 15:16:56 GMT" },
{ "name":"loop0", "type":"other", "mtime":"Mon, 23 Oct 2017 15:16:56 GMT" }
// and so forth
]

There could be other examples for "type":"other", if you know some, please leave a comment!

Special dot-current/dot-parent (., ..) and Dot-files/dot-folders (.hidden) are filtered (not present) in the response!
Interesting: special dot-current/dot-parent (., ..) can be added by your clientside code, just as the ngx_http_autoindex_module has hardcoded them into the default html-format response.


Here are two 'raw' response examples in their original 'formatting'.
Note: response line-endings are hardcoded as CRLF.

JSON (and JSONP without callback):

[
{ "name":"subdir", "type":"directory", "mtime":"Tue, 24 Oct 2017 16:16:16 GMT" },
{ "name":"image.jpg", "type":"file", "mtime":"Tue, 24 Oct 2017 16:16:39 GMT", "size":5 },
{ "name":"test.html", "type":"file", "mtime":"Tue, 24 Oct 2017 16:09:18 GMT", "size":5 }
]

JSONP (with callback=foo):
note: the leading block-comment is part of the JSONP response.

/* callback */
foo([
{ "name":"subdir", "type":"directory", "mtime":"Tue, 24 Oct 2017 16:16:16 GMT" },
{ "name":"image.jpg", "type":"file", "mtime":"Tue, 24 Oct 2017 16:16:39 GMT", "size":5 },
{ "name":"test.html", "type":"file", "mtime":"Tue, 24 Oct 2017 16:09:18 GMT", "size":5 }
]);



A painfully simple snippet consuming a JSONP callback and building a HTML table intended to unambiguously clarify the format:

<script>
function foo(d){
  var i= 0
  ,   L= d.length
  ,   r= '<table border="1" cellpadding="4px" style="border-collapse:collapse"><thead style="border-bottom:4px solid black">\n'
       + '<tr><th style="width:80%">Name</th><th>Type</th><th>Last Modified</th><th>Size</th></tr>\n'
       + '</thead><tbody>\n'
  ;
  for(;i<L;++i)
    r+= '<tr><td>'  + d[i].name
      + '</td><td>' + d[i].type
      + '</td><td style="white-space: nowrap">' + d[i].mtime
      + '</td><td>' + (d[i].type==='file' ? d[i].size : '-')
      + '</td></tr>\n';

  r+='</tbody></table>';
  document.body.innerHTML=r;
}
</script>

<script> // JSONP        Use your own preferred JSON(P) fetchmethod
/* callback */
foo([
{ "name":"subdir", "type":"directory", "mtime":"Tue, 24 Oct 2017 16:16:16 GMT" },
{ "name":"image.jpg", "type":"file", "mtime":"Tue, 24 Oct 2017 16:16:39 GMT", "size":5 },
{ "name":"test.html", "type":"file", "mtime":"Tue, 24 Oct 2017 16:09:18 GMT", "size":5 },
{ "name":"????", "type":"other", "mtime":"Tue, 24 Oct 2017 16:17:52 GMT" }
]);
</script>

That means that from here on you could filter and sort your results client-side. Also you could link up icons depending on file-type/extension etc.
Make it as wild as you'd like, good luck!

Some extra inspiration might be found in:

  • nginx-autoindex-js (a JavaScript frontend for Nginx JSON autoindex format)
  • or pretty-autoindex
    (currently has a 'bug': it hides size when type=directory instead of correct behavior of hiding size when type!=file)

Sources:

  • excellent help on the #nginx communitiy support IRC channel (on freenode) from user 'benbrown', thanks for the help in testing and pointing me to the relevant parts of the nginx source code
  • http://lxr.nginx.org/ident?_i=ngx_http_autoindex_json
  • http://lxr.nginx.org/source/src/http/modules/ngx_http_autoindex_module.c#0693
  • official unit tests: https://trac.nginx.org/nginx/browser/nginx-tests/autoindex_format.t


回答3:

Solved the problem by adding a php script to the server to list the files.