How to deal with 405 Method Not Allowed error in Tomcat + JSP

There is a problem that PUT and DELETE methods cannot be used when running JSP on Tomcat 8 or later.

https://stackoverflow.com/questions/23886941/http-status-405-jsps-only-permit-get-post-or-head

Due to this limitation, when you make a request to a JSP with the PUT or DELETE method, 405 Method Not Allowed is returned. Since it is blocked at the container level, changing the processing and settings of the Servlet has no effect.

This issue can be overcome with HTTP method overrides. However, allowing PUT and DELETE may cause security problems, so please judge the application of this method at your own risk.

HTTP method override

It's easy to do, just add x-http-method to the header and access with the POST method.

PUT issuance example


curl -X POST -H "Content-Type:application/json" -H "x-http-method:PUT" -d "<data>" "<API URL>"

However, some HTTP clients may not have the function to rewrite the header. In that case, you can handle it by adding the following servlet filter on the server side.

Servlet filter

The Servlet filter is a mechanism that allows processing to be inserted between the Servlet container and the Servlet, and can perform pre-processing of requests for Web applications and post-processing of responses.

It implements the HTTP method override described above. This allows the container to accept PUT or DELETE as POST and pass it to the Servlet as PUT or DELETE.

Creating a Servlet filter

Filter sample source

Below is the sample source code of the filter that executes the HTTP method override.

package test;

import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class MethodConvertingFilter implements Filter {
    @Override
    public void init(FilterConfig config) throws ServletException {
        // do nothing
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        chain.doFilter(wrapRequest((HttpServletRequest) request), response);
    }

    @Override
    public void destroy() {
        // do nothing
    }

    private static HttpServletRequestWrapper wrapRequest(HttpServletRequest request) {
        return new HttpServletRequestWrapper(request) {
            @Override
            public String getMethod() {
            	//Returns that this request is POST if the request method is PUT or DELETE
            	if(request.getMethod().equalsIgnoreCase("PUT") || request.getMethod().equalsIgnoreCase("DELETE")) {
            		return "POST";
            	}
                return request.getMethod();
            }

            @Override
            public String getHeader(String name) {
            	// x-http-Set the original method in the method header
            	if(name.equalsIgnoreCase("x-http-method")) {
            		return request.getMethod();
            	}
            	return super.getHeader(name);
            }

            @Override
            public Enumeration getHeaderNames() {
                List<String> names = Collections.list(super.getHeaderNames());
                // x-http-Added method header
                names.add("x-http-method");
                return Collections.enumeration(names);
            }
        };
    }
}

Filter class placement

Compile the filter source and place the generated class files in your web application's WEB-INF/classes.

Add filter definition

Add the following filter definition to web.xml. If multiple filters are defined, the processing will be applied in the defined order, so pay attention to the definition position.


  <filter>
    <filter-name>MethodConvertingFilter</filter-name>
    <filter-class>test.MethodConvertingFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>MethodConvertingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher> 
  </filter-mapping>

This completes the implementation. You will be able to perform PUT and DELETE normally.

Recommended Posts

How to deal with 405 Method Not Allowed error in Tomcat + JSP
How to switch Tomcat context.xml with WTP in Eclipse
`bind': Address already in use --bind (2) for 127.0.0.1:3000 (Errno :: EADDRINUSE) How to deal with the error
How to deal with Selenium :: WebDriver :: Error :: UnknownError that occurs in Dokcer environment etc.
How to deal with errors in Rails s could not find a JavaScript runtime.
How to deal with the error ERROR: While executing gem ... (Gem :: FilePermissionError)
Android: How to deal with "Could not determine java version from '10 .0.1'"
Project facet Java version 13 is not supported. How to deal with
[Java] How to compare with equals method
[Android] How to deal with dark themes
How to have params in link_to method
How to deal with Precompiling assets failed.
How to display error messages in Japanese
How to avoid exceptions with Java's equals method
[Laravel] How to deal with out of memory error when composer require [Docker]
[Rails] How to operate the helper method used in the main application with Administrate
How to embed JavaScript variables in HTML with Thymeleaf
How to implement UICollectionView in Swift with code only
How to sort in ascending / descending order with SQLite
How to call functions in bulk with Java reflection
Diet program with preprocessor (how to deal with i-appli size)
How to deal with fatal: remote origin already exists.
How to deal with No template for interactive request
How to use Z3 library in Scala with Eclipse
[Docker environment] How to deal with ActiveSupport :: MessageEncryptor :: InvalidMessage
Organized how to interact with the JDK in stages
[Docker] How to update using a container on Heroku and how to deal with Migrate Error
[How to insert a video in haml with Rails]
[Rails] How to deal with URL changes after render
How to delete untagged images in bulk with Docker
How to mock a super method call in PowerMock
How to use JDD library in Scala with Eclipse
How to query Array in jsonb with Rails + postgres
Common problems with WSL and how to deal with them
[Docker + Rails] How to deal with Rails server startup failure
[Rails] How to solve the error "undefined method` visit'" when using Capybara with Rspec
How to resolve SSL_connect error in PayPal Ruby SDK
How to deal with the error yaml.scanner.ScannerError: while scanning for the next token that appeared in Rails environment construction with Docker
How to get the class name / method name running in Java
How to use the getter / setter method (in object orientation)
What to do when Method not found in f: ajax
How to get values in real time with TextWatcher (Android)
How to test a private method with RSpec for yourself
How to not describe priority, lastmod, changefreq in gem sitemap_generator
Mapping to a class with a value object in How to MyBatis
How to deal with Bundler :: Dsl :: DSLError by rewriting gemfile
How to fix Android apps crashing with RenderThread mystery error
How to set up a proxy with authentication in Feign
How to register as a customer with Square using Tomcat
How to deal with different versions of rbenv and Ruby
How to number (number) with html.erb
How to update with activerecord-import
How to create a method
Android: How to deal with "Cause: cannot find android.support.transition.R $ id 2: android.support.transition.R $ id found in android / support / transition / R $ id 2.class"
[Java] How to search for a value in an array (or list) with the contains method
How to deal with the event that Committee :: InvalidRequest occurs in committee during Rspec file upload test
How to make a jar file with no dependencies in Maven
How to POST JSON in Java-Method using OkHttp3 and method using HttpUrlConnection-
How to create your own Controller corresponding to / error with Spring Boot
How to switch Java version with direnv in terminal on Mac
How to run a job with docker login in AWS batch