Grails上的静态文件需要一段时间才能通过http协议进行访问

时间:2015-04-10 15:23:38

标签: tomcat grails

我有一个Grails 2.3.7应用程序用于存储许多文件,用户可以通过URL下载他们的文件。但是,当他们进行上传并尝试通过生成的URL立即访问上传的文件时,获取" NOT FOUND"错误。如果他们等待一秒钟,他们可以正常访问该文件。

enter image description here

我重新加载相同的网址后很少...

enter image description here

我不知道它是资源的Grails框架处理器还是Tomcat 7的文件系统安全系统。我已经删除了Grails插件的资源(资源:1.2.14)来做这个测试。以下是我的BuildConfig.groovy:

grails.servlet.version = "3.0" // Change depending on target container compliance (2.5 or 3.0)
grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.work.dir = "target/work"
grails.project.target.level = 1.6
grails.project.source.level = 1.6
//grails.project.war.file = "target/${appName}-${appVersion}.war"

grails.project.fork = [
    // configure settings for compilation JVM, note that if you alter the Groovy version forked compilation is required
    //  compile: [maxMemory: 256, minMemory: 64, debug: false, maxPerm: 256, daemon:true],

    // configure settings for the test-app JVM, uses the daemon by default
    test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true],
    // configure settings for the run-app JVM
    run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    // configure settings for the run-war JVM
    war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, forkReserve:false],
    // configure settings for the Console UI JVM
    console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]
]

grails.project.dependency.resolver = "maven" // or ivy
grails.project.dependency.resolution = {
    // inherit Grails' default dependencies
    inherits("global") {
        // specify dependency exclusions here; for example, uncomment this to disable ehcache:
        // excludes 'ehcache'
    }
    log "error" // log level of Ivy resolver, either 'error', 'warn', 'info', 'debug' or 'verbose'
    checksums true // Whether to verify checksums on resolve
    legacyResolve false // whether to do a secondary resolve on plugin installation, not advised and here for backwards compatibility

    repositories {
        inherits true // Whether to inherit repository definitions from plugins

        grailsPlugins()
        grailsHome()
        mavenLocal()
        grailsCentral()
        mavenCentral()
        // uncomment these (or add new ones) to enable remote dependency resolution from public Maven repositories
        //mavenRepo "http://repository.codehaus.org"
        //mavenRepo "http://download.java.net/maven/2/"
        //mavenRepo "http://repository.jboss.com/maven2/"

        mavenRepo "http://repo.spring.io/milestone/"
    }

    dependencies {
        // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
        // runtime 'mysql:mysql-connector-java:5.1.27'
        // runtime 'org.postgresql:postgresql:9.3-1100-jdbc41'
        runtime  'postgresql:postgresql:9.1-901.jdbc4'
    }

    plugins {
        // plugins for the build system only
        build ":tomcat:7.0.53"

        // plugins for the compile step
        compile ":scaffolding:2.0.3"
        compile ':cache:1.1.2'

        // Plugin to validate CPF/CNPJ/CEP
        compile ":br-validation:0.3"

        compile ":spring-security-core:2.0-RC2"
        compile ":spring-security-rest:1.3.4", {
            excludes: 'spring-security-core'
        }

        // Excel, Excel 2007 & CSV Importer Using Apache POI
        compile ":joda-time:1.5"
        compile ":excel-import:1.0.0"

        // Plugin to send emails
        compile ":mandrill:0.5"

        // Plugin to generate PDF
        compile ":wkhtmltopdf:0.1.7"

        // Plugin to scale images
        compile ":hd-image-utils:1.1"

        // Plugin to schedule jobs
        compile ":quartz:1.0.2"

        // plugins needed at runtime but not for compilation
        runtime ":hibernate:3.6.10.9" // or ":hibernate4:4.3.4"
        runtime ":database-migration:1.3.8"
        runtime ":jquery:1.11.0.2"
        // Resources com webxml
        //runtime ":resources:1.2.14"
        compile ":webxml:1.4.1"
        // Uncomment these (or add new ones) to enable additional resources capabilities
        //runtime ":zipped-resources:1.0.1"
        //runtime ":cached-resources:1.1"
        //runtime ":yui-minify-resources:0.1.5"

        // An alternative to the default resources plugin is the asset-pipeline plugin
        //compile ":asset-pipeline:1.6.1"

        // Uncomment these to enable additional asset-pipeline capabilities
        //compile ":sass-asset-pipeline:1.5.5"
        //compile ":less-asset-pipeline:1.5.3"
        //compile ":coffee-asset-pipeline:1.5.0"
        //compile ":handlebars-asset-pipeline:1.3.0.1"
    }
}

我的Config.grooy:

import java.text.SimpleDateFormat

// locations to search for config files that get merged into the main config;
// config files can be ConfigSlurper scripts, Java properties files, or classes
// in the classpath in ConfigSlurper format

// grails.config.locations = [ "classpath:${appName}-config.properties",
//                             "classpath:${appName}-config.groovy",
//                             "file:${userHome}/.grails/${appName}-config.properties",
//                             "file:${userHome}/.grails/${appName}-config.groovy"]

// if (System.properties["${appName}.config.location"]) {
//    grails.config.locations << "file:" + System.properties["${appName}.config.location"]
// }

grails.project.groupId = appName // change this to alter the default package name and Maven publishing destination

// The ACCEPT header will not be used for content negotiation for user agents containing the following strings (defaults to the 4 major rendering engines)
grails.mime.disable.accept.header.userAgents = ['Gecko', 'WebKit', 'Presto', 'Trident']

// URL Mapping Cache Max Size, defaults to 5000
//grails.urlmapping.cache.maxsize = 1000

// enable only when you need it
//grails.resources.resourceLocatorEnabled = true

// What URL patterns should be processed by the resources plugin
grails.resources.adhoc.includes = ['**/images/**', '**/upload/**', '**/profile/**', '**/users/**', '**/photos/**', '/css/**', '/js/**', '/plugins/**']
grails.resources.adhoc.patterns = ['/images/*', '/upload/*', '/profile/*', '/users/*', '/photos/*', '/css/*', '/js/*', '/plugins/*']
//grails.resources.processing.enabled = false
//grails.resources.adhoc.patterns = []
//grails.resources.rewrite.css = false

// uri-to-url resolution cache timeout in milliseconds
// 0 == caching disabled , -1 == no timeout
grails.resources.uriToUrlCacheTimeout = 30000

// Legacy setting for codec used to encode data with ${}
//grails.views.default.codec = "html"

// The default scope for controllers. May be prototype, session or singleton.
// If unspecified, controllers are prototype scoped.
grails.controllers.defaultScope = 'singleton'

// GSP settings
grails {
    views {
        gsp {
            encoding = 'UTF-8'
            htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
            codecs {
                expression = 'html' // escapes values inside ${}
                scriptlet = 'html' // escapes output from scriptlets in GSPs
                taglib = 'none' // escapes output from taglibs
                staticparts = 'none' // escapes output from static template parts
            }
        }
        // escapes all not-encoded output at final stage of outputting
        // filteringCodecForContentType.'text/html' = 'html'
    }
}

grails.converters.encoding = "UTF-8"
// scaffolding templates configuration
grails.scaffolding.templates.domainSuffix = 'Instance'

// Set to false to use the new Grails 1.2 JSONBuilder in the render method
grails.json.legacy.builder = false
// enabled native2ascii conversion of i18n properties files
grails.enable.native2ascii = true
// packages to include in Spring bean scanning
grails.spring.bean.packages = []
// whether to disable processing of multi part requests
grails.web.disable.multipart=false

// request parameters to mask when logging exceptions
grails.exceptionresolver.params.exclude = ['password']

// configure auto-caching of queries by default (if false you can cache individual queries with 'cache: true')
grails.hibernate.cache.queries = false

// configure passing transaction's read-only attribute to Hibernate session, queries and criterias
// set "singleSession = false" OSIV mode in hibernate configuration after enabling
grails.hibernate.pass.readonly = false
// configure passing read-only to OSIV session by default, requires "singleSession = false" OSIV mode
grails.hibernate.osiv.readonly = false

grails.plugin.wkhtmltox.binary = "/usr/local/bin/wkhtmltopdf"

grailsApplication.config.hashCode = '2wg2+(APd;&[Ya9'

grails.regex.emailPattern = /[^\s][_A-Za-z0-9-]*@[A-Za-z0-9]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})/

grails.regex.cpfORcnpj = /([0-9]{2}[\.][0-9]{3}[\.][0-9]{3}[\\\/][0-9]{4}[-][0-9]{2})|([0-9]{3}[\.][0-9]{3}[\.][0-9]{3}[-][0-9]{2})/

grails.regex.cpf = /([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})/

grails.regex.cnpj = /([0-9]{2}[\.]?[0-9]{3}[\.]?[0-9]{3}[\\/]?[0-9]{4}[-]?[0-9]{2})/

grails.regex.is.file = /^[\w|\W]*(\.)[a-zA-Z0-9]*/

grails.regex.is.url = /^(http|https|ftp)?\:?(\/\/)?[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?\/?([a-zA-Z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/

grails.regex.filesFolder = /^([image|upload]*)\/[\w]*/

grails.statics.ementa = "Ementa - "

environments {
    development {
        grails.logging.jul.usebridge = true
        sassPath = 'sass'
        courseThemeFolder = "css/"
        uploadFolder = "upload/"
        documentsFolder = "documents/"
        meetingsFolder = "meetings/"
        courseLogoUploadFolder = "images/upload/courses/logos/"
        educationalProjectUploadFolder = "upload/offers/educational_projects/"
        generalSettingsUploadFolder = "upload/general/settings/institution/"
        programOfStudiesUploadFolder = "upload/offers/program_of_studies/"
        meetingTriggersUploadFolder = "upload/meetings/triggers/"
        photosUploadFolder = "upload/users/profile/photo/"
        forumAttachmentFileFolder = "upload/forum/%s/%s/attachments/%s/"
        documentVersionFileFolder = "upload/%s/%s/%s/documents/%s/%s/"
        temporaryFilesFolder = "upload/tmp/"
        grails.serverURL = "http://localhost:8080/"
        grails.staticUrl = "http://localhost:8080/pemaap/"
    }
    production {
        grails.logging.jul.usebridge = false
        sassPath = '/usr/local/bin/sass'
        courseThemeFolder = "css/"
        uploadFolder = "upload/"
        documentsFolder = "documents/"
        meetingsFolder = "meetings/"
        courseLogoUploadFolder = "images/upload/courses/logos/"
        educationalProjectUploadFolder = "upload/offers/educational_projects/"
        generalSettingsUploadFolder = "upload/general/settings/institution/"
        programOfStudiesUploadFolder = "upload/offers/program_of_studies/"
        meetingTriggersUploadFolder = "upload/meetings/triggers/"
        photosUploadFolder = "upload/users/profile/photo/"
        forumAttachmentFileFolder = "upload/forum/%s/%s/attachments/%s/"
        documentVersionFileFolder = "upload/%s/%s/%s/documents/%s/%s/"
        temporaryFilesFolder = "upload/tmp/"
    }
}

mandrill {
    apiKey = "0DltTv2M1K6YiSTchRYarg"
}

// log4j configuration
log4j = {
    String fileName = new SimpleDateFormat("yyyy-MM-dd'.txt'").format(new Date());
    appenders {
        file name:'file', file:'/var/tmp/logs/pemaap.erros.log'
        environments {
            development {
                rollingFile name: "file", maxFileSize: 1024,
                            file: ("/tmp/dev/logs/" + fileName)
            }
            production {
                rollingFile name: "file", maxFileSize: 1024,
                            file: ("/tmp/prod/logs/" + fileName)
            }
        }
    }
    root {
        error 'stdout', 'file'
    }
}

// Added by the Spring Security Core plugin:
grails.plugin.springsecurity.userLookup.userDomainClassName = 'br.com.tokenlab.pemaap.User'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'br.com.tokenlab.pemaap.UserAccessProfile'
grails.plugin.springsecurity.authority.className = 'br.com.tokenlab.pemaap.AccessProfile'
grails.plugin.springsecurity.rest.login.useJsonCredentials = true
grails.plugin.springsecurity.logout.postOnly = false
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
    '/':                              ['permitAll'],
    '/index':                         ['permitAll'],
    '/index.gsp':                     ['permitAll'],
    '/**/js/**':                      ['permitAll'],
    '/**/css/**':                     ['permitAll'],
    '/**/images/**':                  ['permitAll'],
    '/**/favicon.ico':                ['permitAll'],
    '/dbconsole/**':                  ['permitAll'],
    '/user/login':                    ['permitAll'],
    '/user/logout':                   ['permitAll'],
    '/**/upload/**':                  ['permitAll'],
    '/**/users/**':                   ['permitAll'],
    '/**/photos/**':                  ['permitAll'],
    '/**/files/**':                   ['permitAll'],
    '/**/tmp/**':                     ['permitAll'],
    '/**/users/**':                   ['permitAll'],
    '**/profile/**':                  ['permitAll'],
    '**/photo/**':                    ['permitAll'],
    '**/upload/users/profile/photo/**':['permitAll']
]

cors.headers = ['Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'origin, authorization, accept, content-type, x-requested-with, X-Auth-Token',
                'Access-Control-Allow-Methods': 'GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS']

accessProfile.type = [
    ["id": "1", "name": "Cliente"],
    ["id": "2", "name": "Prestador de Serviço"]
]

alternative.text = [
    ["text": "Satisfatório / Insatisfatório / Sem emissão de conceito", "alternatives": ["Satisfatório", "Insatisfatório", "Sem emissão de conceito"]],
    ["text": "Satisfatório / Insatisfatório", "alternatives": ["Satisfatório", "Insatisfatório"]]
]

email.sender.address = "iep@tokenlab.com.br"
//email.sender.address = "ufscar@tokenlab.com.br"

format.assessmentCategory = [
    ["id": "1", "name": "Formativa"],
    ["id": "2", "name": "Somativa"]
]

format.category = [
    ["id": "1", "name": "Avaliação de Atividade"],
    ["id": "2", "name": "Avaliação de Curso"],
    ["id": "3", "name": "Avaliação de Desempenho de Pessoas"]
]

format.defaultConcepts = [
    [
        "id": "0",
        "concepts": [
            "Satisfatório",
            "Insatisfatório",
            "Sem emissão de conceito"
        ]
    ],
    [
        "id": "1",
        "concepts": [
            "Satisfatório",
            "Insatisfatório"
        ]
    ],
    [
        "id": "2",
        "concepts": [
            "Satisfatório",
            "Precisa melhorar",
            "Sem emissão de conceito"
        ]
    ],
    [
        "id": "3",
        "concepts": [
            "Satisfatório",
            "Precisa melhorar"
        ]
    ],
    [
        "id": "4",
        "concepts": [
            "Satisfatório",
            "Insatisfatório",
            "Não utilizei",
            "Sem emissão de conceito"
        ]
    ],
    [
        "id": "5",
        "concepts": [
            "Satisfatório",
            "Insatisfatório",
            "Não compareci",
            "Sem emissão de conceito"
        ]
    ],
    [
        "id": "6",
        "concepts": [
            "Satisfatório",
            "Insatisfatório",
            "Não se aplica",
            "Sem emissão de conceito"
        ]
    ]
]

individualPerson.gender = ["Masculino", "Feminino"]

meeting.movements = ["Avaliação", "Nenhum"]

offer.schemes = ["Anual", "Ciclo", "Semestral"]

offer.attendanceSchemes = ["Anual", "Semestral", "Todo o Curso"]

question.types = [
    ["id": "1", "name": "Dissertativa"],
    ["id": "2", "name": "Objetiva - Múltipla Escolha"],
    ["id": "3", "name": "Objetiva - Resposta Única"]
]

PS:文件存储在与网络应用程序相同的计算机上,位于同一个域中,但存储在其他端口中。上传的文件被ascyncron进程上传移动到grails web-app文件夹内的系统文件夹中。前端应用程序向grails后端应用程序发送请求并等待一些响应。在这段时间,grails尝试上传文件并将其移动到最终文件夹。

1 个答案:

答案 0 :(得分:0)

如果您需要上传文件,那么在Amazon S3存储桶中有一个很好的选择。有一些插件可以帮助他们轻松实现,而且您永远不必担心丢失文件,而且成本非常低。

https://grails.org/plugin/aws-sdk