You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rack应用设置Content-Type后浏览器显示MIME类型为空的问题

Rack应用MIME类型显示不一致问题排查

问题描述

编写了一个Rack应用,代码如下:

class Responder
  def self.call(env)
    path = env['PATH_INFO']
    path = File.extname(path).blank? ? 'index.html' : path
    extension = File.extname(path)
    headers = {
      'Content-Type' => Rack::Mime.mime_type(extension)
    }
   [200, headers, [ File.read(File.join(APP_ROOT, path)) ] ]
  end
end

设计目标:

  • 无扩展名路由(如/foo、/bar)返回index.html
  • 带扩展名请求(如.js、.css)直接返回对应文件

curl测试时响应头Content-Type正常:

curl -i http://localhost:3000/foo
HTTP/1.1 200 OK
Content-Type: text/html
curl -i http://localhost:3000/main.js
HTTP/1.1 200 OK
Content-Type: application/javascript

但浏览器访问时,加载模块脚本的<script>标签报错:

main.js:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.

原因分析

核心问题是代码中使用了String#blank?方法,该方法属于Rails的ActiveSupport扩展,并非Ruby标准库原生方法:

  • curl测试时,环境可能加载了ActiveSupport(比如在Rails开发环境中运行),blank?可以正常调用,代码逻辑执行无误,Content-Type设置正确。
  • 浏览器访问时,应用在纯Rack环境(未加载ActiveSupport)运行,调用blank?会抛出NoMethodError异常。Rack默认的错误处理返回的响应未正确设置Content-Type,导致浏览器检测到MIME类型为空。

解决方案

将blank?替换为Ruby标准库支持的方法,比如empty?:

class Responder
  def self.call(env)
    path = env['PATH_INFO']
    # 用empty?替代blank?,适配纯Ruby环境
    path = File.extname(path).empty? ? 'index.html' : path
    extension = File.extname(path)
    headers = {
      'Content-Type' => Rack::Mime.mime_type(extension)
    }
   [200, headers, [ File.read(File.join(APP_ROOT, path)) ] ]
  end
end

如果需要处理包含空白字符的扩展名(比如路径是/foo.这种情况),可以改用strip.empty?:

path = File.extname(path).strip.empty? ? 'index.html' : path

另外,建议添加错误处理逻辑,避免文件读取失败时返回异常响应:

class Responder
  def self.call(env)
    path = env['PATH_INFO']
    path = File.extname(path).empty? ? 'index.html' : path
    file_path = File.join(APP_ROOT, path)
    
    unless File.exist?(file_path)
      return [404, {'Content-Type' => 'text/plain'}, ['File not found']]
    end

    extension = File.extname(path)
    headers = {
      'Content-Type' => Rack::Mime.mime_type(extension) || 'text/plain'
    }
    
    [200, headers, [ File.read(file_path) ] ]
  end
end

内容的提问来源于stack exchange,提问作者patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:35:22