侧边栏壁纸
博主头像
风过江南乱的博客

行动起来,活在当下

  • 累计撰写 3 篇文章
  • 累计创建 4 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

nginx 实现随机图片api

风过江南乱
2025-04-05 / 0 评论 / 1 点赞 / 51 阅读 / 0 字

1、安装并启用Nginx的JavaScript模块

  • 以Ubuntu为例。

    sudo apt-get install nginx-module-njs  
    systemctl restart nginx
  • 查看检查Nginx是否加载了JavaScript模块

    nginx -V
  • 在输出中查找--add-module=ngx_http_js_module,如果没有找到,说明js模块未被加载。

2、在Nginx配置文件中加载JavaScript模块

  • 修改nginx.conf,默认在/etc/nginx目录下

    load_module modules/ngx_http_js_module.so;
  • 重载nginx配置

    nginx -s reload;

3、创建图片目录

  • 假设图片目录为/images,新建update_image_list.sh手动生成一个文件列表文件。

    #!/bin/bash
    ​
    IMAGE_DIR="/etc/nginx/images" # 自定义图片目录
    LIST_FILE="/etc/nginxl/image_list.txt"
    TEMP_LIST_FILE=$(mktemp) # 使用临时文件避免并发问题
    ​
    # 查找指定类型的常规文件,并只输出文件名
    find "$IMAGE_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.png" -o -iname "*.webp" \) -printf "%f\n" > "$TEMP_LIST_FILE"
    ​
    # 原子地替换旧列表文件
    if [ -s "$TEMP_LIST_FILE" ]; then # 确保临时文件不为空
        mv "$TEMP_LIST_FILE" "$LIST_FILE"
        # 确保 nginx 用户可以读取该文件
       # chown nginx:nginx "$LIST_FILE"
        chmod 777 "$LIST_FILE"
    else
        echo "Warning: No images found or error generating list. Keeping old list if exists."
        rm "$TEMP_LIST_FILE" # 清理空的临时文件
    fi
    ​
    exit 0

4、在Nginx配置文件中引用JavaScript脚本文件

  • 创建/etc/nginx/js/fs.js文件并在nginx中引用。

    js_import /etc/nginx/js/fs.js;
  • 编辑fs.js,处理随机从文件列表image_list.txt中读取并返回访问路径。

    import fs from 'fs';
    ​
    function random_redirect(r) {
        const listFile = 'image_list.txt'; // 指向预生成的文件列表,自定义目录
    ​
        try {
            // 1. 读取预生成的列表文件内容
            // 注意:readFileSync 在 njs 中返回 Buffer,需要转为 String
            const fileContent = fs.readFileSync(listFile).toString('utf8');
    ​
            // 2. 将内容按行分割成数组,并过滤掉空行
            const files = fileContent.split('\n').filter(file => file.trim() !== '');
    ​
            // 3. 检查结果
            if (files.length === 0) {
                r.error(`No image filenames found in ${listFile}`);
                return r.return(404, "No image filenames found in list file");
            }
    ​
            // 4. 随机选择一个文件名
            const randomFile = files[Math.floor(Math.random() * files.length)];
    ​
            // 5. 生成完整URL跳转
            // 使用 r.variables.scheme 获取当前协议 (http or https) - 更健壮
            // 或者直接硬编码 https 如果你只用 https
            const scheme = r.variables.scheme || 'https';
            const target = `${scheme}://${r.headersIn.host}/images/${randomFile}`;
    ​
            // 6. 设置响应头并返回 302
            r.headersOut['Location'] = target;
            r.status = 302; // 直接设置状态码
            r.sendHeader();  // 发送头部
            r.finish();      // 结束请求 (对于 302 通常不需要发送 body)
            // 或者更简洁的方式:
            // r.headersOut['Location'] = target;
            // r.return(302); // njs 会处理好头部和结束请求
    ​
        } catch (e) {
            // 记录更详细的错误到 Nginx error log
            r.error(`Error processing random redirect: ${e.message} ${e.stack}`);
            // 返回通用错误给客户端
            return r.return(500, `Server Error: Failed to process request.`);
        }
    }
    ​
    // 确保导出正确
    export default { random_redirect };
  • 重载nginx配置

    nginx -s reload;

5、创建访问路径

  • 新建img-api.conf

    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        http2 on;
        server_name xxxxxxx.com;
    ​
        # SSL 配置
        ssl_certificate /xxxxx/cert.pem;
        ssl_certificate_key /xxxxx/cert.key;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; 
        ssl_ciphers HIGH:!aNULL:!MD5:!RC4:!DHE;
        ssl_prefer_server_ciphers on;
        client_max_body_size 1024m;
        location /images {
            alias /etc/nginx/images;
            expires 10m;
            access_log off;
        }
        # 随机跳转接口
        location = /random {
            # 禁用干扰头
            proxy_set_header Accept-Encoding "";
            add_header Cache-Control no-store;
    ​
            # 调用JS处理
            js_content fs.random_redirect;
            
            # 清除默认错误页
            default_type "";
        }
    }
    ​
    # HTTP 跳转到 HTTPS
    server {
        listen 80;
        listen [::]:80;
        server_name xxxxxx.com;
        return 301 https://$host$request_uri;  # 更简洁的重定向
    }
    ​
  • 重载nginx配置。

    nginx -s reload;

6、结束

  • 访问https://xxxxx.com/random会302跳转到https://xxxxx.com/images/xxxx.png这种。

1

评论区