class SitemapsController < ApplicationController include SitemapsHelper before_action :set_bucket_name def index @sitemaps = list_sitemaps respond_to do |format| format.html format.xml { render_sitemap_index } end rescue Aws::S3::Errors::ServiceError => e Rails.logger.error "S3 Error: #{e.message}" render status: :internal_server_error end def show path = params[:path] key = "sitemaps/#{path}" Rails.logger.info "Requesting sitemap: #{path}" begin # 检查文件是否存在 s3_client.head_object( bucket: @bucket_name, key: key ) # 生成预签名URL,设置15分钟有效期 signer = Aws::S3::Presigner.new(client: s3_client) url = signer.presigned_url( :get_object, bucket: @bucket_name, key: key, expires_in: 15 * 60, # 15 minutes # response_content_type: 'application/xml', # 确保正确的内容类型 response_content_disposition: "inline" # 在浏览器中直接显示 ) # 设置缓存头 response.headers["Cache-Control"] = "public, max-age=3600" # 1小时缓存 # 重定向到预签名URL redirect_to url, allow_other_host: true, status: :found rescue Aws::S3::Errors::NotFound Rails.logger.error "Sitemap not found: #{path}" render status: :not_found rescue Aws::S3::Errors::ServiceError => e Rails.logger.error "S3 Error: #{e.message}" render status: :internal_server_error end end # def show # path = params[:path] # Rails.logger.info "Sitemap: #{path}" # begin # response = s3_client.get_object( # bucket: @bucket_name, # key: "sitemaps/#{path}" # ) # expires_in 12.hours, public: true # content_type = response.content_type || "application/xml" # send_data( # response.body.read, # filename: path, # type: content_type, # disposition: "inline" # ) # rescue Aws::S3::Errors::NoSuchKey # render status: :not_found # rescue Aws::S3::Errors::ServiceError => e # Rails.logger.error "S3 Error: #{e.message}" # render status: :internal_server_error # end # end private def set_bucket_name @bucket_name = Rails.env.production? ? ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)) : ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:minio_dev, :bucket)) end def s3_client @s3_client ||= Aws::S3::Client.new end def list_sitemaps response = s3_client.list_objects_v2( bucket: @bucket_name, prefix: "sitemaps/" ) response.contents.map do |object| { key: object.key.sub("sitemaps/", ""), last_modified: object.last_modified, size: object.size, url: sitemap_url(object.key.sub("sitemaps/", "")) } end.reject { |obj| obj[:key].empty? } end def render_sitemap_index base_url = "#{request.protocol}#{request.host_with_port}" builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| xml.sitemapindex(xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9") do @sitemaps.each do |sitemap| xml.sitemap do xml.loc "#{base_url}/sitemaps/#{sitemap[:key]}" xml.lastmod sitemap[:last_modified].iso8601 end end end end render xml: builder.to_xml end end