如何在Elastic Beanstalk中链接应用目录外的路径?
这个问题我之前在Elastic Beanstalk上部署Rails应用时也碰到过,核心原因是Web服务器(比如Nginx或Apache)只会暴露应用根目录以内的静态资源,你直接在视图里写/tmp/...的路径,Web服务器会去应用根目录下的tmp文件夹找文件,而不是系统级的/tmp目录,自然会提示“文件未找到”。下面给你几个可行的解决方案:
方案一:通过控制器动作代理文件下载(最可靠)
这是最通用的方法,让Rails控制器读取系统/tmp里的文件,再把内容发送给用户,绕开Web服务器的静态资源限制:
添加控制器动作
在你的项目控制器(比如ProjectsController)里新增一个处理下载的动作:def download_kml file_path = "/tmp/#{params[:project_id]}/doc.kml" if File.exist?(file_path) # 设置文件类型和下载文件名 send_file file_path, filename: "#{@project.name}_doc.kml", content_type: 'application/vnd.google-earth.kml+xml', disposition: 'attachment' else flash[:alert] = "下载文件不存在" redirect_back fallback_location: projects_path end end配置路由
在config/routes.rb里添加对应的路由:resources :projects do get 'download_kml', on: :member end修改视图链接
把原来的链接替换成路由辅助方法生成的路径:<%= link_to 'Download KML', download_kml_project_path(@project), download: true %>权限检查
确保Web服务器运行的用户(Elastic Beanstalk上一般是nginx或apache)有读取/tmp下目标文件的权限——通常/tmp是全局可读的,不过如果你在/tmp下创建了子目录,记得设置权限为755,避免权限不足。
方案二:使用持久化存储(推荐长期方案)
要注意:Elastic Beanstalk的EC2实例/tmp目录是临时存储,实例重启、终止或者自动缩放时,文件都会丢失;如果是多实例环境,用户可能访问到没有生成文件的实例,照样下载失败。
所以更稳妥的做法是把生成的文件上传到AWS S3,然后给用户提供S3的下载链接(或者用控制器代理S3文件的下载):
- 生成文件后,用AWS SDK把文件上传到S3的某个存储桶
- 在视图里直接链接到S3的文件URL(需要确保文件有公开读取权限,或者用预签名URL做临时授权)
- 或者用控制器动作生成S3预签名URL,再跳转到该URL下载
方案三:单实例临时方案(不推荐多实例)
如果你的应用是单实例部署,且暂时不想改S3,可以把生成的文件放到应用根目录下的public/tmp文件夹(需要先创建这个目录),这样Web服务器就能直接访问了。但记住:多实例环境下这个方法完全不可用,因为文件只存在于生成它的那个实例上。
内容的提问来源于stack exchange,提问作者Luke Rogers

