Http 重定向到Https,post请求被强制转换为get请求的解决方案

背景

由于公司的项目需要部署到tomcat 中,且要对外提供https的访问,所以我按照网上的教程,自己制作自签名证书,导入到tomcat 中,这个详细的步骤网上有大把的教程,这里不再赘述。证书配置好后,能够访问,由于需要将以http访问的请求重定向到https,所以我又在tomcat 中的web.xml中配置了如下信息:

  <login-config>  
      
    <auth-method>CLIENT-CERTauth-method>  
    <realm-name>Client Cert Users-only Arearealm-name>  
login-config>  
<security-constraint>  
      
    <web-resource-collection >  
        <web-resource-name >SSLweb-resource-name>  
        <url-pattern>/*url-pattern>  
    web-resource-collection>  
    <user-data-constraint>  
        <transport-guarantee>CONFIDENTIALtransport-guarantee>  
    user-data-constraint>  
security-constraint>

配置之后,确实生效。http get 请求 都能被重定向到https get 上,但是 http post 请求 死活不行,后台老是报requestMethod GET not supported,我访问的是post 方法呀,怎么就变成了get,百思不得其解,后来看到一篇博客讲到nginx做转发的时候也有这种问题,看了一下他的解决方法。

server {
listen 80;
server_name *.snsprj.cn;
return 307 https:// host h o s t request_uri;
}

我首先注意到了307 状态码,于是我想看一下我用tomcat 配置的它默认返回的状态码是多少
Http 重定向到Https,post请求被强制转换为get请求的解决方案_第1张图片
从上图中可以看出状态码是302,由于本人知识面比较窄,并不知道302,307的代表含义,于是就去查询相关资料,摘自wikipedia

302 Found
要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。[20]由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
新的临时性的URI应当在响应的Location域中返回。除非这是一个HEAD请求,否则响应的实体中应当包含指向新的URI的超链接及简短说明。
如果这不是一个GET或者HEAD请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将302响应视作为303响应,并且使用GET方式访问在Location中规定的URI,而无视原先请求的方法。因此状态码303和307被添加了进来,用以明确服务器期待客户端进行何种反应。

看到这里就明白了为什么http post 请求重定向时会被变成http get 请求。

307 Temporary Redirect
在这种情况下,请求应该与另一个URI重复,但后续的请求应仍使用原始的URI。 与302相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个POST请求来重复POST请求

解决办法

由于我使用的是tomcat 进行重定向的,从上文中也可以看出tomcat 默认进行的是302重定向,不符合我们的需求,那又什么办法可以解决呢?办法就是不用tomcat提供的配置,那就是我们自己后台程序处理,毕竟用人家的受限制,自己搞,想怎么弄就怎么弄。自己做的话很明显需要一个过滤器,在请求到达sevlet 之前进行处理,代码如下:

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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
@WebFilter(urlPatterns="/*",filterName="HttpsFilter")
/**
 *  过滤器,将http 请求转发到https请求上来
 *  重定向类型:307
 * @author FrankYuan
 *
 */
public class HttpsFilter implements Filter{
    private Logger logger = LoggerFactory.getLogger(HttpsFilter.class);
    private static final String HTTPS ="https";
    private static final int HTTPS_PORT = 8443;
    @Override
    public void destroy() {
        logger.info("------------destroy HttpsFilter --------------");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
         URL newUrl = null;
         if(request.getScheme().equals(HTTPS)) {
             chain.doFilter(request, response);
         }else {
             HttpServletRequest httpRequest = (HttpServletRequest)request;
             HttpServletResponse httpResponse = (HttpServletResponse)response;
             String queryString = httpRequest.getQueryString()==null ? "":"?"+httpRequest.getQueryString();
             httpResponse.setStatus(307);
             String requestUrl = httpRequest.getRequestURL().toString();
             URL reqUrl = new URL(requestUrl+queryString);
             logger.info("【original request-】 "+reqUrl.toString());
             newUrl = new URL(HTTPS,reqUrl.getHost(),HTTPS_PORT,reqUrl.getFile());
             //进行重定向
             logger.info("【new request-】 "+newUrl.toString());
             httpResponse.setHeader("Location", newUrl.toString());
             httpResponse.setHeader("Connection", "close");
             //允许所有跨域请求
             httpResponse.addHeader("Access-Control-Allow-Origin", "*");     
         }

    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        logger.info("------------init HttpsFilter --------------");

    }

}

注意:这里又个坑,就是重定向后需要也需要解决跨域问题,不然页面ajax请求 http 地址会出现跨域问题。

关键代码

httpResponse.setStatus(307);

将响应码换成307

你可能感兴趣的:(Java)