@
jindeq @
void1900 @
hxy100 直接用 nginx 源码讲话。
首先说明 nginx 的默认配置 mime.types ,内容如:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
...
存储在 nginx 内存中方存放的方式为:
[
'html' => 'text/html',
'htm' => 'text/html',
'shtml' => 'text/html',
'css' => 'text/css',
'xml' => 'text/xml',
...
]
也就是['ext' => 'mime']这种格式,从这里就很清楚了,mime 和文件后缀可以互相替代,但是 mime 不是文件后缀,你完全可以在这个文件里添加一条
text/html v2ex;
此后后缀为".v2ex"的文件 nginx 返回时 response 的 Content-type 就会设置成 text/html
liuxu@liuxu-VirtualBox:/etc/nginx$ cat mime.types | grep v2ex
text/html v2ex;
liuxu@liuxu-VirtualBox:/etc/nginx$ ls -l /var/www/html/
total 12
-rw-r--r-- 1 root root 612 10 月 26 21:47 index.nginx-debian.html
-rw-r--r-- 1 root root 11 10 月 26 23:34 test.v2ex
liuxu@liuxu-VirtualBox:/etc/nginx$ file /var/www/html/index.nginx-debian.html
/var/www/html/index.nginx-debian.html: HTML document, ASCII text
liuxu@liuxu-VirtualBox:/etc/nginx$ file /var/www/html/test.v2ex
/var/www/html/test.v2ex: ASCII text
liuxu@liuxu-VirtualBox:/etc/nginx$ cat /var/www/html/test.v2ex
I'm liuxu.
liuxu@liuxu-VirtualBox:/etc/nginx$ curl -v http://127.0.0.1/test.v2ex
* Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
> GET /test.v2ex HTTP/1.1
> Host: 127.0.0.1
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.18.0 (Ubuntu)
< Date: Tue, 26 Oct 2021 15:35:53 GMT
< Content-Type: text/html
< Content-Length: 11
< Last-Modified: Tue, 26 Oct 2021 15:34:36 GMT
< Connection: keep-alive
< ETag: "6178200c-b"
< Accept-Ranges: bytes
<
I'm liuxu.
* Connection #0 to host 127.0.0.1 left intact
在有了以上说明后,下面从 nginx 源码说话:
1. nginx 不设置 default_type 时,response 的 Content-Type 默认是 text/plain ,而不是 application/octet-stream 。也就是说单独一个 nginx 运行,root 目录为 /var/www/html/时,把 test.php 放入 /var/www/html/下,会直接打印代码。
https://github.com/nginx/nginx/blob/41a241b3ef74dbbe3d82ab2ebbe682919e4a0b90/src/http/ngx_http_core_module.c#L36932. nginx 设置了 default_type 为 application/octet-stream ,按 1 的配置,浏览器访问 1.php ,Content-Type 因为是 application/octet-stream 所以会下载该文件。当然也不止 application/octet-stream ,还有如果有 Content-Disposition 的话也会调用下载任务。
https://en.wikipedia.org/wiki/MIME3. nginx 引入了自己的默认配置文件 mime.types 后,ngx_http_set_content_type()首先走到 1606 行判断有没有文件后缀,如果有后缀,则会走到 1633 ,从后缀中搜索 type ,也就是前面说的在 nginx 内存结构中的 mime.types:
type = ngx_hash_find(&clcf->types_hash, hash,
r->exten.data, r->exten.len)
if (type) {
r->headers_out.content_type_len = type->len;
r->headers_out.content_type = *type;
return NGX_OK;
}
但是由于 mime.types 中没有 php 相关的配置,也就是不存在一个"type/xxx php"这样的配置,所以如果没有设置 location ~ \.php${...}这类配置,php 文件就会被下载。
以下是返回 response 的代码:
https://github.com/nginx/nginx/blob/41a241b3ef74dbbe3d82ab2ebbe682919e4a0b90/src/http/ngx_http_core_module.c#L1593所以 nginx 并没有通过 mime 来区分返回 response ,而是通过文件后缀查询到了对应的 mime ,然后设置了到 Content-type 然后返回。
最后说一下 location ~ \.php${...}中,.php 是不是后缀匹配。从人为理解来说是匹配.php 后缀文件,但是从 nginx 的角度来看,它就是一个正则字符串,并没有在内部 mime 列表中查出一个['php'=>'type/php']这种东西。