ssm项目开发过程中跨域问题解决

在写这学期课设时,页面没有采用jsp,前端是对床在他本子上写的,我提供了url给他,他的ajax请求后后台却返回了403,但是这时候我写的jsp测试却没有问题,开始怀疑是表单提交和ajax提交的请求类别不同,于是在网上搜,果然找到了一些线索:

  1. 当请求方法不是GET\POST\HEAD之一或者请求类型不是application/x-www-form-urlencoded、multipart/form-data、text/plain之一时,请求就是复杂请求
    而ajax请求的类型是application/json,也就是json。这时的请求自然就是复杂请求了,至于复杂请求到底复杂在哪了,我猜是不是因为json结构可以很复杂。
  2. 这就涉及到安全问题了,为了安全同源策略规定浏览器对跨域的请求有不同的处理:
    如果是跨域的简单请求则
    浏览器在请求头中加上Origin头后直接发送,Origin对应的值为请求方的域名。服务器发现请求头中有Origin字段,就会验证对应域名是否是被允许的,然后进行相应处理。**
    如果是复杂请求,则浏览器会先发一个预检请求,类型为OPTIONS,询问服务器是否该域名被允许发送请求,如果允许,则浏览器收到回应后,会发送真正的请求,这一切对用户而言都是隐藏的。
    服务器对跨域请求的响应头中有以下内容:
    Access-Control-Allow-Origin:服务器允许跨域请求的域名
    Access-Control-Expose-Headers:允许返回给跨域请求的响应头列表
    Access-Control-Max-Age:预检请求返回的结果的有效时间,有效时间内浏览器不用再次向服务器发送预检请求
    Access-Control-Allow-Credentials:告知浏览器当withCredentials属性设置为true时,是否可以显示跨域请求返回的内容。简单请求时,浏览器会根据此响应头决定是否显示响应的内容。预先验证请求时,浏览器会根据此响应头决定在发送实际跨域请求时,是否携带认证信息。
    Access-Control-Allow-Methods:服务端支持的请求方法
    Access-Control-Allow-Headers:服务端支持的请求头

知道了这些,那问题就容易解决了,我们可以在后台设置一个拦截器,拦截带有Origin字段的请求头,并给响应头中加入那些字段,设置为相应的值。

package gh.ttms.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class OptionsInterceptor implements HandlerInterceptor {
    //private List excludedUrls;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        if (httpServletRequest.getHeader("Origin")!=null){
            httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
            httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
            httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
            httpServletResponse.setHeader("Access-Control-Allow-Headers",
                    "Origin, X-Requested-With, Content-Type, Accept");
            
        }
        
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

//    public List getExcludedUrls() {
//        return excludedUrls;
//    }
//
//    public void setExcludedUrls(List excludedUrls) {
//        this.excludedUrls = excludedUrls;
//    }

}

tips:

  1. 这里有一个小问题就是如果设置了Access-Control-Allow-Credentials为true,则Access-Control-Allow-Origin不能设为*
  2. 跨域就是不同域之间的交互,域名不同或域名相同端口不同等都属于不同域,更多请自行百度
  3. 网上有说配置的,但是这个好像对复杂请求没啥用,可能是因为对复杂请求浏览器会发送预检请求吧
  4. 我还试过直接针对OPTIONS类型的请求写了个Controller,如下,作用是给响应头中加那些字段,最后记得字段加进去了但跨域请求还是403,目前还不知道为啥
package gh.ttms.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletResponse;

@Controller
public class OptionsInterceptor {

    @RequestMapping(value = "/**",method = RequestMethod.OPTIONS)
    public void handler(HttpServletResponse response)
    {
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Methods","*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept");

    }
}

你可能感兴趣的:(java)