nginx如何读取缓存文件

m

1. 一些和文件操作相关的函数

(1)ngx_file_info

             宏定义: #define ngx_file_info(file, sb) stat((const car*)file, sb)

stat函数 :具体用法见 http://wenku.baidu.com/view/31777dc1d5bbfd0a795673b1.html

(2)ngx_open_file(name,mode,create,access)

宏定义 : #define ngx_open_file(name,mode,create,access) open((const char*) name, mode|create, access);

open函数: http://baike.baidu.com/view/26337.htm


2. nginx如何读取缓存文件 

之前紧紧大致弄明白了upstream的工作流程,可一谈到细节,依然是一头雾水。

例如,nginx如何读取缓存文件?今天继续看源代码,希望能够找到答案。

(1)打开缓存文件

在ngx_http_file_cache.c中

ngx_http_file_cache_open() {

……//打开或是创建内存结点

if (ngx_open_cached_file(clcf->open_file_cache,&c->file.name,&of,r->pool) != NGX_OK) {

}

c->file.fd = of.fd;//保存缓存文件的文件句柄

c->uniq = of.uniq;//保存缓存文件的inode节点号

c->length = of.size;//保存缓存文件的大小(字节)

c->buf = ngx_create_temp_buf(r->pool,c->body_start)//这个buf中不知存储着什么????

 

}

这个ngx_open_cached_file似乎和打开缓存文件有关,于是深入地查看一下。

ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool) {

if (cache == NULL) {

if (of->test_only) {}//不会执行这个if语句

rc = ngx_open_and_stat_file(name->data, of, pool->log);

if (rc == NGX_OK && !of->is_dir) {

clnf->fd = of ->fd;//保存打开文件的句柄

clnf->name = name->data;//保存文件路径

}

}

}

再看ngx_open_and_stat_file() {

……

fd = ngx_open_file(name,….)//打开缓存文件

……

of->fd = fd;//将文件句柄保存于of

}

(2) 利用缓存文件响应客户端

ngx_http_upstream_cache() {

……

case NGX_OK:

rc = ngx_http_upstream_cache_send(r,u);

}

ngx_http_upstream_cache_send() {

……

ngx_http_cache_send();

}

ngx_http_cache_send() {

ngx_buf_t *b;

ngx_chain_t out;

c = r->cache;

b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

if (b == NULL) {

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

b->file = ngx_pcalloc(r->pool,sizeof(ngx_file_t));

if (b->file == NULL) {

return NGX_HTTP_INTERNAL_SERVER_ERROR;

}

b->file_pos = c->body_start;

b->file_last = c->length;

b->in_file = 1;

b->last_buf = (r==r->main)?1:0;

b->last_in_chain;

b->file->fd = c->file.fd;

b->file->name = c->file.name;

b->file->log = r->connection->log;

out.buf = b;

out.next = NULL;

return ngx_http_output_filter(r,&out);

}

(3) 自己使用缓存文件响应客户

a.缓存文件的结构:

缓存文件的第一部分存储着关于ngx_http_file_cache_header_t这个结构的数据。

typedef struct {

time_t    valid_sec;

time_t    last_modified;

time_t    date;

uint32_t crc32;

u_short  valid_msec;

u_short  header_start;//缓存文件中,存放HTTP头的起始位置

u_short  body_start;//存放HTTP body的起始位置

缓存文件的第二部分是KEY,例如KEY:http://主机IP/相对路径/文件名 , 如果客户端拥有

相同的KEY,那么客户端使用同一个缓存。

第三部分是源服务器的响应头,这部分内容可存储到结构

第四部分是源服务器的响应体。

b. 缓存文件的文件名: r->cache->file.name.data,可以通过此文件名打开缓存。

c.    打开文件,获得文件句柄

ngx_fd_t fd;

fd = ngx_open_file(r->cache->file.name.data, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,NGX_FILE_OPEN, 0);

if (fd == NGX_INVALID_FILE) {

//打开失败

}

d.    获取文件信息

ngx_file_info_t fi;

if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {

//获取信息失败

ngx_close_file(fd);

}

e. 获取文件信息后提取有效信息

int length;

if (ngx_is_dir(&fi)) {

ngx_close_file(fd);//如果打开的是文件夹

} else {

length  = ngx_file_size(&fi);//打开文件的字节数

}

f. 申请空间,以读取缓存文件

u_char *buf = ngx_palloc(pool,   u->conf->buffer_size);

ssize_t n;

#if (NGX_HAVE_PREAD)

n = pread(fd, buf, u->conf->buffer_size,0);

#else

n = read(fd,buf,u->conf->buffer_size);

#endif

if (n == -1) {

ngx_close_file(fd);//读取出错

}

g. 分析缓存文件的第一部分

ngx_http_file_cache_header_t *h;

h = (ngx_http_file_cache_header_t *) buf;

size_t body_start = h->body_start;

size_t header_start = h->header_start;

h. 读取缓存的body

u_char *sbuf = ngx_palloc(pool, length – body_start);

n = pread(fd, cbuf, length-body_start, body_start);
i. 使用ngx_http_send_header()和ngx_http_output_filter()发送HTTP数据。


### 解决 Nginx 配置中因 `location` 重复定义导致的 404 错误 当在 Nginx 中配置多个 `location` 块时,可能会因为不当的配置引发 404 错误。这种情况通常与以下几个方面相关:请求未正确匹配到预期的 `location` 块、前端框架路由机制未能有效支持以及 `location` 块间的优先级冲突。 --- #### 1. **分析 404 错误的原因** Nginx 返回 404 错误意味着服务器找不到对应的资源来处理用户的请求。这可能发生在以下场景下: - 用户请求的路径未匹配任何有效的 `location` 块。 - 资源确实不存在于指定的根目录或路径中[^5]。 - 对于基于前端框架的应用程序(如 Vue.js),刷新页面可能导致后端无法识别动态路由并返回 404[^2]。 此外,如果存在重复定义的 `location` 块,Nginx 可能会选择错误的一个进行处理,从而进一步加剧问题。 --- #### 2. **解决 404 错误的方法** 以下是几种常见的解决方案,适用于不同的情况: ##### 方法一:统一处理前端应用的动态路由 对于使用 Vue.js 或 React 等前端框架构建的应用程序,在部署至 Nginx 时需特别注意动态路由的支持。可以通过如下配置实现所有未知路径均指向 `index.html`,交由前端路由器解析: ```nginx server { listen 80; server_name localhost; root /path/to/vue/app/dist; // 设置Vue项目的dist目录作为根目录[^1] index index.html; location / { try_files $uri $uri/ /index.html; // 动态路由支持 } } ``` 上述配置确保即使用户访问 `/about` 这样的路径,也会被重定向到 `index.html` 并由前端框架接管。 --- ##### 方法二:合理划分多个 `location` 块 如果需要在一个 `server` 块中管理多个独立的服务(例如 PC 版本和移动端版本),应明确区分各部分的功能范围。例如: ```nginx server { listen 80; server_name example.com; # PC版站点 location /pc/ { alias /data/html/pc/; // 使用alias而非root以避免路径拼接问题 index index.html; try_files $uri $uri/ /pc/index.html; // 支持PC版的动态路由 } # 移动端站点 location /h5/ { alias /data/html/h5/; // 同样使用alias index index.html; try_files $uri $uri/ /h5/index.html; // 支持移动端的动态路由 } } ``` 在此基础上,确保每个 `location` 块内的逻辑清晰无歧义,防止相互干扰。 --- ##### 方法三:利用正则表达式精确控制特定资源 对于一些特殊需求(比如图片缩放或自动生成404页面),可借助正则表达式的强大能力定制化处理规则。例如: ```nginx # 图片重写示例 location ~* ^/images/(.+)\.(jpg|png)$ { rewrite ^/images/(.*)_(\d+)x(\d+)\.(jpg|png)$ /resizer/$1.$4?width=$2&height=$3 break; // 缩放图像[^3] proxy_pass http://backend-resizer; } # 自定义404页面 error_page 404 /custom_404.html; location = /custom_404.html { internal; // 仅内部跳转可用 root /var/www/errors; // 自定义错误页位置 } ``` --- #### 3. **验证配置有效性** 完成修改后务必执行以下操作验证配置是否生效: 1. 测试语法正确性: ```bash nginx -t ``` 2. 若无误,则重新加载 Nginx 配置使改动即时生效: ```bash sudo systemctl reload nginx ``` --- ### 示例完整配置 综合考虑以上几点,下面提供一份完整的 Nginx 配置模板供参考: ```nginx server { listen 80; server_name example.com; root /var/www/example.com/public_html; // 主网站根目录 index index.html; # 处理前端应用的动态路由 location / { try_files $uri $uri/ /index.html; // 动态路由支持[^2] } # 子模块分离 location /api/ { proxy_pass http://localhost:3000/api/; // API代理到Node.js服务 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 静态资源优化 location /static/ { expires max; // 开启缓存 add_header Cache-Control public; } # 错误页面自定义 error_page 404 /errors/custom_404.html; location = /errors/custom_404.html { internal; root /var/www/example.com; } } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值