代码之家  ›  专栏  ›  技术社区  ›  so_mv

HTTP多部分/混合xml部分与其他部分混合时能否转换为哈希

  •  0
  • so_mv  · 技术社区  · 15 年前

    问题就在最后一段代码的上面。非常感谢。 (环境细节到此为止)

    岗位_控制器.rb

    class PostsController < ApplicationController  
    def create
        @post = Post.new(params[:post])
        respond_to do |format|
          format.xml { render :xml => @post.to_xml(:include => [ :assets])}
    end
    end
    

    class Post < ActiveRecord::Base
      has_many    :assets, :as => :attachable, :dependent => :destroy
    end
    

    资产.rb

    class Asset < ActiveRecord::Base
      belongs_to :attachable, :polymorphic => true
      has_attached_file :data,
                        :url  => "/assets/:id",
                        :path =>":rails_root/assets/:id_partition/:style/:basename.:extension"
      def name
        data_file_name
      end
    
      def content_type
        data_content_type
      end
    
      def file_size
        data_file_size
      end
      end
    

    现在当我们发布这些信息

    POST /posts.xml HTTP/1.1
    Accept-Encoding: gzip,deflate
    Accept: application/xml
    Content-Type: application/xml
    User-Agent: Jakarta Commons-HttpClient/3.1
    Host: localhost:8080
    Content-Length: 60
    
    <post><body>postbody</body><title>post_title</title></post>
    

    将创建一个post条目 当我发这个的时候

    POST /posts.xml HTTP/1.1
    Content-type: multipart/mixed; boundary=---------------------------7d226f700d0
    Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    Cache-Control: no-cache
    Pragma: no-cache
    User-Agent: Java/1.6.0_21
    Host: 192.168.0.105:8080
    Connection: keep-alive
    Content-Length: 1710
    
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[title]"
    Content-Length: 10
    post_title
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[body]"
    Content-Length: 8
    postbody
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/files/1.txt"
    content-type: application/octet-stream
    ÿþ
    sample file content
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/Pictures/1.txt"
    content-type: application/octet-stream
    ÿþ
    sample file content
    -----------------------------7d226f700d0
    

    现在的问题是,我想获得以下HTTP post(请注意文件附件之前的xml部分)来创建一个包含2个附件的post,而不需要额外更改(posts\u controller或路由.rb). 有可能吗?

    POST /posts.xml HTTP/1.1
    Content-type: multipart/mixed; boundary=---------------------------7d226f700d0
    Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    Cache-Control: no-cache
    Pragma: no-cache
    User-Agent: Java/1.6.0_21
    Host: 192.168.0.105:8080
    Connection: keep-alive
    Content-Length: 1710
    
    -----------------------------7d226f700d0
    Content-type: application/xml; charset=UTF-8
    Content-Length: 59
    <post><body>postbody</body><title>post_title</title></post>
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/files/1.txt"
    content-type: application/octet-stream
    ÿþ
    sample file content
    -----------------------------7d226f700d0
    content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/Pictures/1.txt"
    content-type: application/octet-stream
    ÿþ
    sample file content
    -----------------------------7d226f700d0Blockquotetest
    

    使用jruby 1.5.2/jdk1.6、rails 2.3.4、回形针2.3.3

    1 回复  |  直到 15 年前
        1
  •  0
  •   so_mv    15 年前

    至少Rails2.3.4不会自动执行此操作。我们需要在initializers/mime中编写一个多部分/相关的解析器并注册它_类型.rb

    注意:请随时更新副本中的硬编码值(如主和附件部分前缀等)。

    同样的策略也可以用于多部分/相关内容。在下面的示例中,我们仍在讨论是使用multipart/related还是multipart/mixed。

    http://msdn.microsoft.com/en-us/library/ms527355(EXCHG.10).aspx

    Mime::Type.register "multipart/mixed", :mixed
    
    class ActionController::Request
      def initialize(env)
        Thread.current[:request]=self
        super
      end
    
    end
    
    class MultiPartParamsParser
    
      def main_part_name
       "main"
      end
    
      def attachment_part_prefix
        "my_company_attachment"
      end
    
      def content_type(main_part)
        # TODO ----
        :xml_simple
      end
    
      def content(main_part)
        # TODO implement this
         if main_part.is_a?(String) 
           main_part.gsub!("Content-Type: application/xml",'') # remove content type if it exists
           main_part.strip! # to remove any trailing or leading whitespaces
         else
          main_part[:tempfile].read
         end
      end
    
      def request
        Thread.current[:request]
      end
    
      def parse_formatted_parameters(data)
        multi_parts = Rack::Utils::Multipart.parse_multipart(request.try(:env))
        main_part   = multi_parts[main_part_name]
        data        = content(main_part)
        # TODO return an error if data is not found
        params = case content_type(main_part)
          when :xml_simple, :xml_node
            data.blank? ? {} : Hash.from_xml(data).with_indifferent_access
          when :yaml
            YAML.load(data)
          when :json
            if data.blank?
              {}
            else
              ret = ActiveSupport::JSON.decode(data)
              ret = {:_json => data} unless data.is_a?(Hash)
              ret.with_indifferent_access
            end
          else
            {}
        end
        process_attachments(params, multi_parts)
        params                 
      end
    
      def process_attachments(data, multi_parts)
        data.each do |key, value|
          value ||= key # when array value is nil
          if value.is_a?(Hash) or value.is_a?(Array)
            process_attachments(value, multi_parts)
          elsif value.respond_to?(:match) and value.match("^#{attachment_part_prefix}") and (attachment=multi_parts[value]) # there could Time,Numbers etc.., but we match only string.
            data[key] = create_uploaded_file(attachment) # TODO handle the scenarios for short strings
          end 
        end         
      end
    
      def create_uploaded_file (attachment)
        upload = attachment[:tempfile]
        upload.extend(ActionController::UploadedFile)
        upload.original_path = attachment[:filename]
        upload.content_type = attachment[:type]
        upload
      end
    end
    
    proc = Proc.new do |data|
      MultiPartParamsParser.new.parse_formatted_parameters(data)
    end
    
    ActionController::Base.param_parsers[Mime::Type.lookup('multipart/mixed')] = proc
    

    然后,你可以像这样发布你的信息。嵌套将自动执行,无需对模型或控制器进行进一步更改。

    POST /posts.xml HTTP/1.1
    Content-type: multipart/mixed; boundary=---------------------------###987612345###
    Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    Cache-Control: no-cache
    Pragma: no-cache
    Connection: keep-alive
    Content-Length: ##
    
    -----------------------------###987612345###
    content-disposition: name="main"
    Content-Length: ##
    <post><title>post_title</title><body>post_body</body>
        <assets_attributes type="array">
                <asset><data>my_company_attachment_0</data> </asset>
                <asset><data>my_company_attachment_1</data> </asset>
        </assets_attributes>
    </post>
    -----------------------------###987612345###
    content-disposition: name="my_company_attachment_0"; filename="C:/Users/mv288/files/1.txt"
    content-type: application/octet-stream
    ÿþ
    sample file content
    -----------------------------###987612345###
    content-disposition: name="my_company_attachment_1"; filename="C:/Users/mv288/Pictures/1.png"
    content-type: image/png
    ÿþ
    sample file content
    -----------------------------###987612345###