Spring Boot报错:Content type 'text/plain;charset=UTF-8'不支持求助
问题描述
通过JavaScript向本地Spring Boot服务器发送POST请求实现登录验证时,后端抛出错误:
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/plain;charset=UTF-8' not supported
已尝试在请求头设置application/json、修改@RequestMapping指定消费application_JSON_Value,问题未解决。同时前端存在await response.json()解析错误。
前后端代码及错误信息
HTML代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>WorkSoftManager - Login</title> <link rel="stylesheet" type="text/css" href="styleLogin.css"> </head> <body> <div class="container"> <h1>WorkSoftManager</h1> <h2>Login</h2> <form id="login-form"> <input type="email" id="username" placeholder="Email" required> <input type="password" id="password" placeholder="Password" required> <button type="submit">Login</button> </form> <p>Don't have an account? <a href="signUp.html">Sign Up</a></p> </div> <script src="script.js"></script> </body> </html>
JavaScript代码
// Create a function to handle the login process async function login(username, password) { try { const response = await fetch('http://localhost:8080/api/login/', { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ 'username' : username, 'password': password }) }); // Check if the response was successful if (!response.ok) { throw new Error('Login failed. Please try again.'); } // Parse the response JSON data const data = await response.json(); // Check if the authentication was successful if (!data.authenticated) { throw new Error('Invalid username or password.'); } // Store the authentication token in local storage localStorage.setItem('token', data.token); // Redirect the user to the loginPage.html page window.location.href = '/loginPage.html'; } catch (error) { // Show an error message alert(error.message); } } // Attach an event listener to the login form submit button document.getElementById('login-form').addEventListener('submit', (event) => { event.preventDefault(); // Get the values of the username and password inputs const username = document.getElementById('username').value; const password = document.getElementById('password').value; // Call the login function with the username and password login(username, password); }); // Create a function to handle the log off process function logOff() { // Remove the authentication token from local storage localStorage.removeItem('token'); // Redirect the user to the login page window.location.href = '/loginPage.html'; } // Attach an event listener to the log off link //document.getElementById('log-off-link').addEventListener('click', logOff);
Spring REST Controller代码
@RestController @RequestMapping("/api") public class WSMController { private Map<String, UserSession> sessions = new HashMap<>(); @Autowired private WSMService service; @PostMapping(value = "/login") public ResponseEntity<String> login(@RequestBody LoginRequest request) { User user = authenticate(request); if (user == null) { return ResponseEntity.badRequest().body("Invalid username or password"); } String token = UUID.randomUUID().toString(); UserSession session = new UserSession(user, token); sessions.put(token, session); return ResponseEntity.ok(token); } @PostMapping("/logoff") public ResponseEntity<String> logoff(@RequestHeader("Authorization") String token) { sessions.remove(token.substring(7)); return ResponseEntity.ok("User logged off successfully"); } @GetMapping("/user") public User getUser(@RequestHeader("Authorization") String token) { UserSession session = sessions.get(token.substring(7)); if (session == null) { return null; } return session.getUser(); } private User authenticate(LoginRequest request) { if(!service.getCredentials(request)) { return null; } return new User(request.getUsername(),request.getPassword()); } }
LoginRequest DTO代码
package com.worksoftmanager.WorkSoftManagerAuthenticator.model; public class LoginRequest { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
后端错误日志
2023-02-06 10:43:10.674 WARN 20380 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/plain;charset=UTF-8' not supported]
测试反馈
- John测试:请求后控制台出现
await response.json()错误 - David测试:请求头实际为
text/plain;charset=UTF-8,与代码中设置的application/json不符
解决方案
1. 移除前端mode: 'no-cors'配置
no-cors模式下,浏览器会强制修改请求头:将Content-Type设为text/plain,同时会屏蔽响应内容的读取权限,导致response.json()解析失败。修改后的fetch配置如下:
const response = await fetch('http://localhost:8080/api/login/', { method: 'POST', // 移除 mode: 'no-cors' headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ 'username' : username, 'password': password }) });
2. 配置Spring Boot跨域(CORS)
移除no-cors后需要后端允许跨域请求,可通过以下两种方式配置:
方式一:Controller级别配置
在WSMController类上添加@CrossOrigin注解:
@RestController @RequestMapping("/api") @CrossOrigin(origins = "http://localhost:你的前端端口") // 替换为实际前端地址 public class WSMController { // ... 原有代码 }
方式二:全局CORS配置
创建全局配置类,统一处理跨域:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:你的前端端口") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*"); } }
3. 后端返回JSON格式响应
当前后端返回的是纯字符串token,前端用response.json()解析会报错,需将响应包装为JSON对象。
步骤1:创建登录响应DTO
package com.worksoftmanager.WorkSoftManagerAuthenticator.model; public class LoginResponse { private String token; private boolean authenticated; public LoginResponse(String token, boolean authenticated) { this.token = token; this.authenticated = authenticated; } // Getters and Setters public String getToken() { return token; } public void setToken(String token) { this.token = token; } public boolean isAuthenticated() { return authenticated; } public void setAuthenticated(boolean authenticated) { this.authenticated = authenticated; } }
步骤2:修改Controller的login方法
@PostMapping(value = "/login") public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) { User user = authenticate(request); if (user == null) { return ResponseEntity.badRequest().body(new LoginResponse(null, false)); } String token = UUID.randomUUID().toString(); UserSession session = new UserSession(user, token); sessions.put(token, session); return ResponseEntity.ok(new LoginResponse(token, true)); }
内容的提问来源于stack exchange,提问作者Gustavo Farias
相关产品推荐
相关产品推荐

