跨域请求解决方法

1.JSONP解决(只支持get方式)

关于跨域请求与jsonp

  1. 跨域:由于受到同源策略(协议、域名、端口三者必须全部相同)的影响,ajax请求会受到限制,要突破这种限制,跨域便产生了。跨域的解决方案有多种,这里不展开阐述,只是针对GET请求中的jsonp跨域解决方案做一下说明。
  2. jsonp,本质上jsonp不是xhr异步请求,就是请求了一个js文件,因此在chrome的network面板中的xhr标签下看不到jsonp的跨域请求,在js标签下能看到。就是利用script标签中src不受同源策略的限制,前端定义了回调函数,请求的js脚本中获取数据,并执行前端的回调函数,因此前后端需要统一定义下回调函数名
  3. .ajaxjsonp .ajax对jsonp进行了封装看起来像是ajax请求。由于jsonp是针对get请求的跨域解决,因此之前的经验告诉我,即使type设置了post,在jsonp的时候,也会自动转换成get,直到有一天踩了个坑。翻看$.ajax模块的源码发现,只有去手动设置crossDomain为true,或者实际上是跨域,才会设置为get。否则还是填入的type
  4. jsonp的实现原理:
    首先在客户端注册一个callback, 然后把callback的名字传给服务器。
    此时,服务器先生成 json 数据。
    然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp.
    最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
    客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动
    态执行回调函数)
    前端代码:
/*  
        //简写形式,效果相同  
        $.getJSON("http://app.example.com/base/json.do?sid=1494&busiId=101&jsonpCallback=?",  
                function(data){  
                    $("#showcontent").text("Result:"+data.result)  
        });  
        */

        $("#jsonBtn").click(function(){
            $.ajax({
                url:"http://localhost:8081/sso1/login/jsonp/1234455431",
                type:"GET",
                dataType:"jsonp",
                jsonp: "callback",服务端用于接收callback调用的function名的参数,自定义的参数名
                jsonpCallback:"weather_callback",   //callback的function名称,自定义的函数名。
                contentType:"application/json",
                data:{},
                success:function(data){
                    alert(data);
                }
                });
        });

后端代码:

@ResponseBody
    @RequestMapping(value="/jsonp/{token}",method=RequestMethod.GET)
    public Object getUserByTokenJsonp(@PathVariable("token") String token, String callback){

        System.out.println("进入jsonP"+":"+callback);

        JsonResult result = null;
        try {
            result = userService.getUserByToken(token);
        } catch (Exception e) {
            e.printStackTrace();
            result = JsonResult.build(500, e.getMessage());
        }
        return result;
        //判断是否为jsonp调用
        /*if (StringUtils.isBlank(callback)) {
            return result;
        } else {
            MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
            mappingJacksonValue.setJsonpFunction(callback);
            return mappingJacksonValue;
        }*/

    }

CORS 跨域

  1. cors与json的对比:
    1.都能解决 Ajax直接请求普通文件存在跨域无权限访问的问题
    2.JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求
    3.使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理
    4.JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS

1.支持多域名配置的CORS Filter

1.在配置maven的pom.xml文件。

<!-- https://mvnrepository.com/artifact/com.thetransactioncompany/cors-filter -->
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.thetransactioncompany/java-property-utils -->
<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>java-property-utils</artifactId>
    <version>1.10</version>
</dependency>

在web.xml文件中配置过滤器。

 <filter>

        <filter-name>CORS</filter-name>

        <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>

        <init-param>

            <param-name>cors.allowOrigin</param-name>

<!-- 可以配置具体的过滤路径,例如   http://192.168.56.129,http://192.168.56.130 -->
            <param-value>*</param-value>

        </init-param>

        <init-param>

            <param-name>cors.supportedMethods</param-name>
         <!-- 允许的方法 -->
            <param-value>GET,POST,HEAD,PUT,DELETE</param-value>

        </init-param>

        <init-param>

            <param-name>cors.supportedHeaders</param-name>

            <param-value>Accept,Origin,X-Requested-With,Content-Type,Last-Modified</param-value>

        </init-param>

        <init-param>

            <param-name>cors.exposedHeaders</param-name>

            <param-value>Set-Cookie</param-value>

        </init-param>

        <init-param>

            <param-name>cors.supportsCredentials</param-name>

            <param-value>true</param-value>

        </init-param>

    </filter>

    <filter-mapping>

        <filter-name>CORS</filter-name>

        <url-pattern>/*</url-pattern>

</filter-mapping>

可以查看源码,也是实现Filter的方法,可以自定义实现:

 public class CORSFilter
/*     */   implements Filter

2.简单的自定义CORSFilter / Interceptor

1.filter(过滤器)
继承OncePerRequestFilter,

public class CORSFilter extends OncePerRequestFilter{

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain arg2)
            throws ServletException, IOException {
        //Access-Control-Allow-Origin只能配置 或者一个域名*
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        arg2.doFilter(request, response);
    }



}

然后,在web.xml文件里配置

    <filter>
        <filter-name>cros</filter-name>
        <filter-class>com.sso2.filter.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>cros</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

就可以,其中,Access-Control-Allow-Origin只能配置 或者一个域名*。

2.interceptor(拦截器)
继承HandlerInterceptor,实现preHandle即可,就是配置参数。

public class CORSIntercor implements HandlerInterceptor{

    private List<String> excludedUrls;
    public List<String> getExcludedUrls() {
        return excludedUrls;
    }
    public void setExcludedUrls(List<String> excludedUrls) {
        this.excludedUrls = excludedUrls;
    }


    /**
     * 
     * @Description: 
     * 在业务处理器处理请求之前被调用 如果返回false 
     * 从当前的拦截器往回执行所有拦截器的afterCompletion(),
     * 再退出拦截器链, 如果返回true 执行下一个拦截器,
     * 直到所有的拦截器都执行完毕 再执行被拦截的Controller
     * 然后进入拦截器链,
     * 从最后一个拦截器往回执行所有的postHandle()
     * 接着再从最后一个拦截器往回执行所有的afterCompletion()
     * 
     * @param  request
     * 
     * @param  response
     * 
     * @return: boolean
     * 
     * @author: SongJia
     * 
     * @date: 2016-6-27 下午4:17:51
     * 
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("================preHandle start============================");
        Collection<String> coll = response.getHeaderNames();
        Iterator<String> it = coll.iterator();
        while (it.hasNext()) {
            String string = (String) it.next();
            System.out.println(string);
        }
        System.out.println("================preHandle end============================");

        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        return true;
    }
    // 在业务处理器处理请求执行完成后,生成视图之前执行的动作
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub

    }
    /**
     * 
     * @Description:
     * 在DispatcherServlet完全处理完请求后被调用
     * 当有拦截器抛出异常时,
     * 会从当前拦截器往回执行所有的拦截器的afterCompletion()
     * 
     * @param request
     * 
     * @param response
     * 
     * @param handler
     * 
     * @param ex
     * 
     * @author: SongJia
     * 
     * @date: 2016-6-27 下午4:27:51
     * 
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("================afterCompletion start============================");
        Collection<String> coll = response.getHeaderNames();
        Iterator<String> it = coll.iterator();
        while (it.hasNext()) {
            String string = (String) it.next();
            System.out.println(string);
        }
        System.out.println("================afterCompletion end============================");

    }

}

然后,在spring mvc里面配置截然器:CORSIntercor

 <!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <!-- 需排除拦截的地址 ,可以配置多个-->  
            <mvc:exclude-mapping path="/" />
            <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
            <bean class="com.sso2.interceptor.CORSIntercor"/>
        </mvc:interceptor>
    </mvc:interceptors>

3.spring注解 @CrossOrigin

可以在Controller类上配置 @CrossOrigin,表名该类下的所有方法都是支持跨域,

@CrossOrigin
@Controller
@RequestMapping("/login")
public class LoginController {

    @Autowired
    private UserService userService;

如果配置在方法上,则是 只有该方法支持跨域。

    @CrossOrigin(origins = "*", maxAge = 3600)
    @ResponseBody
    @RequestMapping(value="/token/{token}",method=RequestMethod.POST)
    public Object getUserByToken(@PathVariable("token") String token, String callback){



        JsonResult result = null;
        try {
            result = userService.getUserByToken(token);
        } catch (Exception e) {
            e.printStackTrace();
            result = JsonResult.build(500, e.getMessage());
        }
        return result;
        //判断是否为jsonp调用
        /*if (StringUtils.isBlank(callback)) {
            return result;
        } else {
            MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
            mappingJacksonValue.setJsonpFunction(callback);
            return mappingJacksonValue;
        }*/

    }

4.Nginx 配置支持Ajax跨域

待定

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值