You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:02:12