【问题标题】:Spring Boot - Post Method Not Allowed, but GET worksSpring Boot - 不允许发布方法,但 GET 有效
【发布时间】:2023-03-12 18:03:01
【问题描述】:

我的 spring boot mysql 项目有问题, 控制器类仅适用于 METHOD GET(get all),但我似乎无法发布 并得到错误 405:不允许方法“POST”

这是我的控制器类:

 package com.example.demo.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.example.demo.Blog;
import com.example.demo.repository.BlogRespository;

import java.util.List;
import java.util.Map;

@RestController
public class BlogController {

    @Autowired
    BlogRespository blogRespository;

    @GetMapping("/blog")
    public List<Blog> index(){
        return blogRespository.findAll();
    }

    @GetMapping("/blog/{id}")
    public Blog show(@PathVariable String id){
        int blogId = Integer.parseInt(id);
        return blogRespository.findById(blogId)
                 .orElseThrow(() -> new IllegalArgumentException(
                 "The requested resultId [" + id +
                 "] does not exist."));
    }

    @PostMapping("/blog/search")
    public List<Blog> search(@RequestBody Map<String, String> body){
        String searchTerm = body.get("text");
        return blogRespository.findByTitleContainingOrContentContaining(searchTerm, searchTerm);
    }

    @PostMapping("/blog")
    public Blog create(@RequestBody Map<String, String> body){
        String title = body.get("title");
        String content = body.get("content");
        return blogRespository.save(new Blog(title, content));
    }

    @PutMapping("/blog/{id}")
    public Blog update(@PathVariable String id, @RequestBody Map<String, String> body){
        int blogId = Integer.parseInt(id);
        // getting blog
        Blog blog = blogRespository.findById(blogId)
             .orElseThrow(() -> new IllegalArgumentException(
             "The requested resultId [" + id +
             "] does not exist."));
        blog.setTitle(body.get("title"));
        blog.setContent(body.get("content"));
        return blogRespository.save(blog);
    }


    @DeleteMapping("blog/{id}")
    public boolean delete(@PathVariable String id){
        int blogId = Integer.parseInt(id);
        blogRespository.delete(blogId);
        return true;
    }


}

如果你需要,这是我的存储库类

package com.example.demo.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.example.demo.Blog;

import java.util.List;

@Repository
public interface BlogRespository extends JpaRepository<Blog, Integer> {

    // custom query to search to blog post by title or content
    List<Blog> findByTitleContainingOrContentContaining(String text, String textAgain);

}

我正在尝试使用 SoapUI 发出 POST 请求,但似乎找不到解决方案,非常感谢

【问题讨论】:

  • 您是否在本地运行应用程序?否则这也可能与服务器限制有关。
  • 您发布到哪种类型或 URL?
  • 你在说@GetMapping("/blog")吗?
  • 您能否使用请求的url 和您要发布的数据的 sn-p 更新问题?
  • 我想同时发布到 /blog 和 /blog/search,当我没有输入正确的信息(帖子中没有字符串)时,它会给出 500 错误,但是当我发送正确的帖子时说不允许 POST 方法

标签: java spring spring-boot jpa


【解决方案1】:

如果您配置或启用了 csrf,则不允许发布方法 那么您需要在发布表单或数据时提供有效的 csrf

为此检查您的 spring 安全配置 例如

    @Configuration
    @EnableWebSecurity
    @ComponentScan(basePackageClasses = CustomUserDetailsService.class)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    .....

RequestMatcher csrfRequestMatcher = new RequestMatcher() {
        // Enabled CSFR protection on the following urls:
        //@formatter:off
        private AntPathRequestMatcher[] requestMatchers = 
            {
                new AntPathRequestMatcher("/**/verify"),
                        new AntPathRequestMatcher("/**/login*")
            };
        //@formatter:off

        @Override
        public boolean matches(final HttpServletRequest request) {
            // If the request match one url the CSFR protection will be enabled
            for (final AntPathRequestMatcher rm : requestMatchers) {
                if (rm.matches(request)) {
                    System.out.println();
                    /* return true; */
                }
            }
            return false;
        } // method matches
    };
@Override
    protected void configure(final HttpSecurity http) throws Exception {
        //@formatter:off

        http.headers().frameOptions().sameOrigin()
        .and()
        .authorizeRequests()
        .antMatchers("/","/css/**", "/static/**", "/view/**", "**/error/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/mvc/login").permitAll() 
        .authenticationDetailsSource(authenticationDetailsSource())
        .successHandler(authenticationSuccessHandler)
        .usernameParameter("username").passwordParameter("password")
        .and()
        .logout().permitAll()
        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        .addLogoutHandler(customLogoutHandler)
        .logoutSuccessHandler(customLogoutSuccessHandler)
        .logoutSuccessUrl("/login?logout")
        .and()
        .exceptionHandling()
        .accessDeniedPage("/403")
                .and()
                .csrf()/* .requireCsrfProtectionMatcher(csrfRequestMatcher) */
        .ignoringAntMatchers("/crud/**","/view/**")
    ;
        // @formatter:off


    }

谢谢

【讨论】:

    【解决方案2】:

    您可能希望考虑搜索方法上的consumes 属性,以告知spring 您希望该方法使用哪个Content-Type。例如@PostMapping(value="/blog/search", consumes=org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE)

    看看org.springframework.http.converter.HttpMessageConverter 的实现。 org.springframework.http.converter.FormHttpMessageConverter impl 之类的东西会将请求正文转换为 MultiValueMap&lt;String,?&gt;

    您也可以按照以下示例进行操作:Spring MVC - How to get all request params in a map in Spring controller?,它使用 @RequestParam 注释而不是 @RequestBody

    您能否发布一个示例 curl 请求来演示 HTTP 405 响应 - 我假设您正在发布到 /blog/search 端点?

    【讨论】:

    • 它说 APPLICATION_FORM_URLENCODED 无法解析为变量
    • 尝试导入常量:org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED
    • 我可以导入org.springframework.http.MediaType,但是不能导入org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED,说不存在
    • APPLICATION_FORM_URLENCODED 是常量,您可以使用 import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE 或者您可以像这样引用它:@PostMapping(value="/blog/search", consumes=org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE) 因为 consumes 属性采用字符串变化。
    • 它现在没有显示错误,但仍然说不允许发布:\ @PostMapping(value="/blog/search", consumes=org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE) public List search(@RequestBody Map body){ String searchTerm = body.get("text");返回 blogRespository.findByTitleContainingOrContentContaining(searchTerm, searchTerm); }
    【解决方案3】:

    我试图通过编写一个虚拟代码来重现该问题,但它对我来说非常好。

    请在下面找到我尝试过的代码 sn-p -

    package com.pradeep.rest.controller;
    
    import java.util.Map;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class RestRequestController {
    
        @GetMapping("/blog")
        public String show() {
            String result = "Hello from show";
            return result;
        }
    
        @PostMapping("/blog")
        public String create(@RequestBody Map<String, String> body) {
            String title = body.get("title");
            String content = body.get("content");
            String result = "title= " + title + " : content= " + content;
            return result;
        }
    }
    

    pom.xml:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.pradeep.rest</groupId>
        <artifactId>RestApi</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.2.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- to ease development environment -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    输入输出sn-p:

    【讨论】:

      【解决方案4】:

      我的试用效果很好Postman

      这是我的控制器。 我跟着这个教程Spring Boot Angular

      package io.crzn.myNotes.controller;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      import javax.validation.Valid;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.http.ResponseEntity;
      import org.springframework.web.bind.annotation.CrossOrigin;
      import org.springframework.web.bind.annotation.DeleteMapping;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.PutMapping;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import io.crzn.myNotes.exception.ResourceNotFoundException;
      import io.crzn.myNotes.model.MyNotes;
      import io.crzn.myNotes.repository.myNotesRepository;
      
      @RestController
      @CrossOrigin(origins = "http://localhost:4200")
      @RequestMapping("/api/v1")
      public class myNotesController {
      
          @Autowired
          private myNotesRepository mynotesRepository;
      
          @GetMapping("/mynotes")
          public List<MyNotes> getAllmyNotes(){
              return mynotesRepository.findAll();
          }
      
          @GetMapping("/mynotes/{id}")
          public ResponseEntity<MyNotes> getEmployeeById(@PathVariable(value = "id") Long mynotesId)
              throws ResourceNotFoundException{
              MyNotes mynotes = mynotesRepository.findById(mynotesId)
                      .orElseThrow(() -> new ResourceNotFoundException("Note not found for this id : :" + mynotesId));
              return ResponseEntity.ok().body(mynotes);
          }
      
          @PostMapping("/mynotes")
          public MyNotes createMyNotes(@Valid @RequestBody MyNotes mynotes) {
              return mynotesRepository.save(mynotes);
          }
      
          @PutMapping("/mynotes/{id}")
          public ResponseEntity<MyNotes> updateMyNotes(@PathVariable(value = "id") Long mynotesId,
                  @Valid @RequestBody MyNotes mynotesDetails)
                          throws ResourceNotFoundException{
              MyNotes mynotes = mynotesRepository.findById(mynotesId)
                      .orElseThrow(() -> new ResourceNotFoundException("Not not found for this id : : " + mynotesId));
      
              mynotes.setstatus(mynotesDetails.getstatus());
              mynotes.setbody(mynotesDetails.getbody());
              mynotes.settitle(mynotesDetails.gettitle());
              final MyNotes updatedMyNotes = mynotesRepository.save(mynotes);
              return ResponseEntity.ok(updatedMyNotes);
          }
      
          @DeleteMapping("/mynotes/{id}")
          public Map<String, Boolean> deleteMyNotes(@PathVariable(value = "id") Long mynotesId)
                  throws ResourceNotFoundException{
              MyNotes mynotes = mynotesRepository.findById(mynotesId)
                      .orElseThrow(() -> new ResourceNotFoundException("Not not found for this id : : " + mynotesId));
      
              mynotesRepository.delete(mynotes);
              Map<String, Boolean> response = new HashMap<>();
              response.put("deleted", Boolean.TRUE);
              return response;
      
          }
      
      
      
      
      }
      

      【讨论】:

        【解决方案5】:

        我遇到了同样的错误,我能够发出 GET 请求,而不允许使用 POST 方法后来我发现在登台服务器中启用了 SSL,所以只是更改了 “http”到“https”并使其工作

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-11-25
          • 2019-04-22
          • 2018-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-27
          • 2021-07-01
          相关资源
          最近更新 更多