Docker部署Spring Boot内嵌Tomcat调用返回401问题求助
Spring Boot容器化后401授权失败与Swagger异常排查
问题现象
- 访问
localhost:8080时,Spring Security弹出登录框,输入账号密码后显示白标错误页;Postman调用任何接口(含GET localhost:8080)均返回401未授权,且Spring Boot无请求日志,最后一条日志为应用启动完成:
2023-03-14T14:11:07.344Z INFO 1 --- [ main] com.example.myapp.MyApplication : Started MyApplication in 3.978 seconds (process running for 4.521)
- 访问Swagger返回空内容,本地运行正常;
- HTTPS访问
localhost:8080时,Spring Boot记录HTTP请求头解析错误:
2023-03-14T14:13:36.511Z INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2023-03-14T14:13:36.513Z INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms 2023-03-14T14:14:02.018Z INFO 1 --- [nio-8080-exec-3] o.springdoc.api.AbstractOpenApiResource : Init duration for springdoc-openapi is: 99 ms 2023-03-14T14:34:55.564Z INFO 1 --- [nio-8080-exec-7] o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level. java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x000xf70x010x000x000xf30x030x03z0xfe0x90q0xe80x0an0x960xd50xcc0xb80x93lv0xfcf0xfc0xf50xdeT0x980xfa0xd6?0x99^0xe70x940x900xcaoP ]. HTTP method names must be tokens at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:419) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:272) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.1.jar!/:na] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-10.1.1.jar!/:na] at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]
环境配置
docker-compose.yml
version: '3.9' services: mongo: image: mongo:4.4.15 restart: unless-stopped environment: MONGO_INITDB_ROOT_USERNAME: root MONGO_INITDB_ROOT_PASSWORD: password ports: - "27017:27017" tty: true stdin_open: true volumes: - mongo-vol:/docker-entrypoint-initdb.d/ healthcheck: test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/test --quiet interval: 10s timeout: 10s retries: 5 start_period: 40s mysql: image: mysql command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_DATABASE: 'mydb' MYSQL_USER: 'user' MYSQL_PASSWORD: 'password' MYSQL_ROOT_PASSWORD: 'password' volumes: - mysql-vol:/docker-entrypoint-initdb.d/ healthcheck: test: /usr/bin/mysql mysql -ppassword --silent --execute "select 1" interval: 10s timeout: 10s retries: 5 my-be: image: be_image container_name: be-container ports: - "8080:8080" environment: spring.datasource.url: "jdbc:mysql://mysql:3306/mydb?allowPublicKeyRetrieval=true&useSSL=false&createDatabaseIfNotExist=true" datasource.driver-class-name: "com.mysql.cj.jdbc.Driver" spring.h2.console.enabled: "false" spring.jpa.database-platform: "org.hibernate.dialect.MySQLDialect" spring.data.mongodb.host: mongo spring.data.mongodb.port: 27017 logging.file.path: logs server.port: 8080 depends_on: mongo: condition: service_healthy mysql: condition: service_healthy volumes: mysql-vol: mongo-vol:
Dockerfile
FROM openjdk:17 EXPOSE 8080 ARG JAR_FILE="target/MyAPP-0.0.1-SNAPSHOT.jar" ADD ${JAR_FILE} app.jar ENTRYPOINT ["java","-jar","/app.jar"]
容器运行状态
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 996da02a43e5 be_image "java -jar /app.jar" 11 minutes ago Up 11 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp be-container 9c3d11ceb0ee mongo:4.4.15 "docker-entrypoint.s…" 11 minutes ago Up 11 minutes (healthy) 0.0.0.0:27017->27017/tcp, :::27017->27017/tcp compose-mongo-1 15fe4d52a50e mysql "docker-entrypoint.s…" 11 minutes ago Up 11 minutes (healthy) 3306/tcp, 33060/tcp compose-mysql-1
排查与解决方案
1. 401未授权及无请求日志问题
原因
- Spring Security启用默认HTTP Basic认证,但未配置合法用户信息,导致登录后授权失败;
- 日志输出到容器内
logs目录,本地无法查看认证失败的详细日志; - 极端情况:应用硬绑定
localhost监听地址,容器外请求无法到达,表现为无日志+401。
解决步骤
- 在
docker-compose.yml的my-be服务中添加Spring Security默认用户配置:environment: # 原有配置... spring.security.user.name: "admin" spring.security.user.password: "admin123" spring.security.user.roles: "ADMIN" server.address: 0.0.0.0 logging.level.org.springframework.security: DEBUG - 执行
docker logs -f be-container查看实时认证日志,定位具体失败原因。
2. Swagger返回空内容问题
原因
- Spring Security拦截了Swagger的静态资源和API文档路径;
- 容器化后Swagger的路径匹配或扫描规则未适配环境。
解决步骤
- 在Spring Security配置类中放行Swagger相关路径:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**") .permitAll() .anyRequest() .authenticated(); } - 若应用有自定义上下文路径,添加环境变量
springdoc.api-docs.path: /v3/api-docs确保Swagger路径正确。
3. HTTPS访问报错问题
原因
应用未配置HTTPS,Tomcat仅监听HTTP端口8080,HTTPS请求的TLS握手数据会被当作非法HTTP请求解析。
解决步骤
- 日常访问使用HTTP协议;若需HTTPS,需在Spring Boot中配置SSL证书,修改
docker-compose.yml的端口映射为443:8443,并添加SSL相关环境变量:environment: # 原有配置... server.ssl.key-store: "/cert/keystore.jks" server.ssl.key-store-password: "your-cert-password" server.port: 8443 volumes: - ./local-cert-path:/cert
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

