flask静态文件部署

flask项目完成,部署到apache时遇到了问题。部分静态文件的content-type没有甚至出现了乱码,浏览器报错content-type mismatch。这是因为链接资源的时候,资源类型已经被标注,比如text/css?然而在http响应头里面却变成其他类型。

对于CSS文件,如果HTTP头里面的content-type标注出错,这会导致浏览器样式表不能够被正确加载。flask内部使用一个函数send_file来返回对静态资源的请求。仔细检查这一函数, flask利用文件名来推测文件的类型,对于猜测出来的多个文件类型,flask会选择第一个作为mimetype。问题出现在什么地方现在并不确定。但是使用apache伺服静态资源可以暂时解决问题。

附源代码

def send_file(filename_or_fp, mimetype=None, as_attachment=False,              attachment_filename=None, add_etags=True,              cache_timeout=None, conditional=False):    """Sends the contents of a file to the client.  This will use the    most efficient method available and configured.  By default it will    try to use the WSGI server's file_wrapper support.  Alternatively    you can set the application's :attr:`~Flask.use_x_sendfile` attribute    to ``True`` to directly emit an `X-Sendfile` header.  This however    requires support of the underlying webserver for `X-Sendfile`.    By default it will try to guess the mimetype for you, but you can    also explicitly provide one.  For extra security you probably want    to send certain files as attachment (HTML for instance).  The mimetype    guessing requires a `filename` or an `attachment_filename` to be    provided.    Please never pass filenames to this function from user sources without    checking them first.  Something like this is usually sufficient to    avoid security problems::        if '..' in filename or filename.startswith('/'):            abort(404)    .. versionadded:: 0.2    .. versionadded:: 0.5       The `add_etags`, `cache_timeout` and `conditional` parameters were       added.  The default behavior is now to attach etags.    .. versionchanged:: 0.7       mimetype guessing and etag support for file objects was       deprecated because it was unreliable.  Pass a filename if you are       able to, otherwise attach an etag yourself.  This functionality       will be removed in Flask 1.0    .. versionchanged:: 0.9       cache_timeout pulls its default from application config, when None.    :param filename_or_fp: the filename of the file to send.  This is                           relative to the :attr:`~Flask.root_path` if a                           relative path is specified.                           Alternatively a file object might be provided                           in which case `X-Sendfile` might not work and                           fall back to the traditional method.  Make sure                           that the file pointer is positioned at the start                           of data to send before calling :func:`send_file`.    :param mimetype: the mimetype of the file if provided, otherwise                     auto detection happens.    :param as_attachment: set to `True` if you want to send this file with                          a ``Content-Disposition: attachment`` header.    :param attachment_filename: the filename for the attachment if it                                differs from the file's filename.    :param add_etags: set to `False` to disable attaching of etags.    :param conditional: set to `True` to enable conditional responses.    :param cache_timeout: the timeout in seconds for the headers. When `None`                          (default), this value is set by                          :meth:`~Flask.get_send_file_max_age` of                          :data:`~flask.current_app`.    """    mtime = None    if isinstance(filename_or_fp, string_types):        filename = filename_or_fp        file = None    else:        from warnings import warn        file = filename_or_fp        filename = getattr(file, 'name', None)        # XXX: this behavior is now deprecated because it was unreliable.        # removed in Flask 1.0        if not attachment_filename and not mimetype \           and isinstance(filename, string_types):            warn(DeprecationWarning('The filename support for file objects '                'passed to send_file is now deprecated.  Pass an '                'attach_filename if you want mimetypes to be guessed.'),                stacklevel=2)        if add_etags:            warn(DeprecationWarning('In future flask releases etags will no '                'longer be generated for file objects passed to the send_file '                'function because this behavior was unreliable.  Pass '                'filenames instead if possible, otherwise attach an etag '                'yourself based on another value'), stacklevel=2)    if filename is not None:        if not os.path.isabs(filename):            filename = os.path.join(current_app.root_path, filename)    if mimetype is None and (filename or attachment_filename):        mimetype = mimetypes.guess_type(filename or attachment_filename)[0]    if mimetype is None:        mimetype = 'application/octet-stream'    headers = Headers()    if as_attachment:        if attachment_filename is None:            if filename is None:                raise TypeError('filename unavailable, required for '                                'sending as attachment')            attachment_filename = os.path.basename(filename)        headers.add('Content-Disposition', 'attachment',                    filename=attachment_filename)    if current_app.use_x_sendfile and filename:        if file is not None:            file.close()        headers['X-Sendfile'] = filename        headers['Content-Length'] = os.path.getsize(filename)        data = None    else:        if file is None:            file = open(filename, 'rb')            mtime = os.path.getmtime(filename)            headers['Content-Length'] = os.path.getsize(filename)        data = wrap_file(request.environ, file)    rv = current_app.response_class(data, mimetype=mimetype, headers=headers,                                    direct_passthrough=True)    # if we know the file modification date, we can store it as the    # the time of the last modification.    if mtime is not None:        rv.last_modified = int(mtime)    rv.cache_control.public = True    if cache_timeout is None:        cache_timeout = current_app.get_send_file_max_age(filename)    if cache_timeout is not None:        rv.cache_control.max_age = cache_timeout        rv.expires = int(time() + cache_timeout)    if add_etags and filename is not None:        rv.set_etag('flask-%s-%s-%s' % (            os.path.getmtime(filename),            os.path.getsize(filename),            adler32(                filename.encode('utf-8') if isinstance(filename, text_type)                else filename            ) & 0xffffffff        ))        if conditional:            rv = rv.make_conditional(request)            # make sure we don't send x-sendfile for servers that            # ignore the 304 status code for x-sendfile.            if rv.status_code == 304:                rv.headers.pop('x-sendfile', None)    return rv

?

?

?

?

flask静态文件部署

相关文章:

你感兴趣的文章:

标签云: