使用過濾器間接實現form表單設定自定義http頭(header)功能
阿新 • • 發佈:2019-02-04
今天專案遇到一個問題,我們專案使用者驗證和許可權驗證的資訊(licence)是在http頭中設定的,百度了一下,只有ajax才能設定頭資訊,form表單是無法設定的,但是我突然想起springMVC關於form表單解決put、delete提交方式的問題,我靈機一動,於是模仿springMVC實現了設定自定義header的功能。
起源
專案使用的是SSM框架,廢話不多說,我們先看springMVC對於form表單提交put、delete請求問題的解決方案,springMVC是使用了一個過濾器,使之用使用者只需在form表單增加一個隱藏域_method即可,比如下面這樣:
_method裡的值就是你要提交方式,具體情況大家自己百度我就細說了。<form id="fm" method="post" > <input type="hidden" name="_method" value="put"/> <input type="hidden" name="_header" value="${licence }"/> <div class="fitem"> <label>uNum:</label> <input name="uNum" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>uPass:</label> <input name="uPass" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>uName:</label> <input name="uName" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>csId:</label> <input name="csId" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>uJob:</label> <input name="uJob" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>uStartTime:</label> <input name="uStartTime" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>rId:</label> <input name="rId" class="easyui-validatebox" required="true"> </div> <div class="fitem"> <label>uMail:</label> <input name="uMail" class="easyui-validatebox" validType="email" required="true"> </div> <div class="fitem"> <label>uState:</label> <input name="uState" class="easyui-validatebox" required="true"> </div> </form>
實現
springmvc在web.xml中配置是這樣的
<filter> <filter-name>httpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>httpMethodFilter</filter-name> <servlet-name>SpringMVC</servlet-name> </filter-mapping>
然後我們來看springMVC的原始碼:
重點我們來看他寫的HttpMethodRequestWrapper這個內部類,這個類繼承HttpServletRequestWrapper,而HttpServletRequestWrapper我進去看了下都是呼叫更上層的方法自己並沒有做什麼事情,再往上我就沒去看了。我理解的他的原理是:request在得到method時時使用getMethod方法的,所以他重寫了getMethod方法,從而可以把_method的值當做method。/* * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.filter; import java.io.IOException; import java.util.Locale; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods, * retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only * support GET and POST, a common technique - used by the Prototype library, for instance - * is to use a normal POST with an additional hidden form field ({@code _method}) * to pass the "real" HTTP method along. This filter reads that parameter and changes * the {@link HttpServletRequestWrapper#getMethod()} return value accordingly. * * <p>The name of the request parameter defaults to {@code _method}, but can be * adapted via the {@link #setMethodParam(String) methodParam} property. * * <p><b>NOTE: This filter needs to run after multipart processing in case of a multipart * POST request, due to its inherent need for checking a POST body parameter.</b> * So typically, put a Spring {@link org.springframework.web.multipart.support.MultipartFilter} * <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain. * * @author Arjen Poutsma * @since 3.0 */ public class HiddenHttpMethodFilter extends OncePerRequestFilter { /** Default method parameter: {@code _method} */ public static final String DEFAULT_METHOD_PARAM = "_method"; private String methodParam = DEFAULT_METHOD_PARAM; /** * Set the parameter name to look for HTTP methods. * @see #DEFAULT_METHOD_PARAM */ public void setMethodParam(String methodParam) { Assert.hasText(methodParam, "'methodParam' must not be empty"); this.methodParam = methodParam; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String paramValue = request.getParameter(this.methodParam); if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method); filterChain.doFilter(wrapper, response); } else { filterChain.doFilter(request, response); } } /** * Simple {@link HttpServletRequest} wrapper that returns the supplied method for * {@link HttpServletRequest#getMethod()}. */ private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { private final String method; public HttpMethodRequestWrapper(HttpServletRequest request, String method) { super(request); this.method = method; } @Override public String getMethod() { return this.method; } } }
那麼既然這樣,我也可以把_header的值當做header啊,而request獲取header的方法是public String getHeader(String name),所以我就寫了下面這樣的過濾器:
package com.zs.tools;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.HiddenHttpMethodFilter;
/**
* 張順,2017-2-28
* 處理form表單頭的過濾器,
* 如果表單有_header欄位,可以自動將該欄位轉為request的header頭資訊(增加一條頭)
* @author it023
*/
public class MyHiddenHttpMethodFilter extends HiddenHttpMethodFilter{
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String header=request.getParameter("_header");
if (header!=null && !header.trim().equals("")) {
HttpServletRequest wrapper = new HttpHeaderRequestWrapper(request,header);
super.doFilterInternal(wrapper, response, filterChain);
}else {
super.doFilterInternal(request, response, filterChain);
}
}
private static class HttpHeaderRequestWrapper extends HttpServletRequestWrapper{
private final String header;
public HttpHeaderRequestWrapper(HttpServletRequest request,String licence) {
super(request);
this.header=licence;
}
@Override
public String getHeader(String name) {
if (name!=null &&
name.equals("licence") &&
super.getHeader("licence")==null) {
return header;
}else {
return super.getHeader(name);
}
}
}
}
然後,在web.xml中配置一下,我是放在HiddenHttpMethodFilter前面的。
<filter>
<filter-name>httpHeaderFilter</filter-name>
<filter-class>com.zs.tools.MyHiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpHeaderFilter</filter-name>
<servlet-name>SpringMVC</servlet-name>
</filter-mapping>