Spring Boot - Post方法不允许,但GET方法可以使用。

3
我在我的Spring Boot MySQL项目中遇到了问题,我的控制器类对于METHOD GET(获取全部)工作正常,但我似乎无法进行POST操作,而且出现错误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请求,但似乎找不到解决方案,感谢您的帮助。


你是在本地运行应用程序吗?否则这也可能与服务器限制有关。 - GiorgosDev
你要发布哪种类型的URL? - Arnaud
你是在谈论 @GetMapping("/blog") 吗? - shahaf
1
你能否更新问题,提供所请求的“url”和您想要发布的数据片段? - Pradeep
你是否在使用SpringSecurity?如果是,你能否检查一下是否启用了CSRF(跨站点资源伪造)? - Supun Dharmarathne
显示剩余3条评论
5个回答

3

如果您配置或启用了csrf,则post方法将不被允许,因此在发布表单或数据时需要提供有效的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的实现将请求体转换为MultiValueMap<String,?>
您还可以参考此示例:Spring MVC - How to get all request params in a map in Spring controller?,该示例使用@RequestParam注释而不是@RequestBody
您能否发布一个演示HTTP 405响应的curl请求示例?我假设您正在发布到/blog/search端点。

它说APPLICATION_FORM_URLENCODED无法解析为变量。 - Drason
尝试导入常量:org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED - David
我可以导入 org.springframework.http.MediaType,但无法导入 org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED,它说不存在。 - Drason
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属性接受字符串形式的值。 - David
现在它没有显示任何错误,但仍然显示该帖子不允许发布:\@PostMapping(value="/blog/search", consumes=org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE) public List search(@RequestBody Map body){ String searchTerm = body.get("text"); return blogRespository.findByTitleContainingOrContentContaining(searchTerm, searchTerm); } - Drason
有什么提示说“不允许发布”。看到一个curl请求的示例会很有用。 - David

0

我尝试通过编写虚拟代码来复现问题,但对我来说完全正常。

请查看下面是我尝试的代码片段 -

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>

输入和输出片段:

enter image description here


0

我遇到过同样的错误,在那里我能够进行GET请求,但是不允许POST方法。后来我发现在暂存服务器上启用了SSL,所以只需将“http”更改为“https”,并使其正常工作即可。


0

我的试验完美地运行了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;

    }




}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接