浏览器 跨域请求问题解决方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013494765/article/details/80367148

浏览器 跨域请求问题解决方法

使用框架:前台AngularJs,后台:Restful+gradle
此方法主要用于前后分离的结构,浏览器火狐:60.0.1

如果你只是想简单点,可以直接使用chrome浏览器,可以直接参考chrome谷歌浏览器Ajax跨域调试问题,不用管它是针对ajax还是其他,都可以使用。因为这是浏览器的配置,与你的前后台无关。其他浏览器是没法用的。

跨域问题怎么出现的?

当浏览器通过 aaa.com 访问 bbb.com时,或者前台和后台不在同一域名下,就会产生跨域问题,
跨域问题是浏览器产生的,浏览器这样设置是为了访问的安全性,本质上与你的前台关系不大,大多是后台进行处理。
火狐现在好像无法通过浏览器配置来允许跨域请求。

浏览器是如何处理跨域的

首先服务器会发送一个预请求 OPTIONS到服务器,服务器处理这个请求(注意这里的服务器处理请求的方法不是实际访问的方法,而是专门用于处理OPTIONS的),判断是否允许进行跨域,将结果加入header返回给浏览器,浏览器解析响应头,如果服务器允许进行跨域,则才会发送真正的get/post请求。
Firefox怎么查看OPtions请求还不请求请自行百度。
浏览器请求服务器的options请求头解析:

Host: 192.168.0.69:18080
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: cache-control,pragma,x-requested-with
Origin: http://localhost:9000

Origin:是客户端的地址
Host: 是请求服务器的地址
后台可以通过 Origin来判断是否允许请求

问题的解决

先学习了解cors原理和restful
参考文档:1.用 Java 技术创建 RESTful Web 服务,了解restful编程规范
2.RESTful API 设计指南这个链接让我知道了@OPTIONS这个注解,以前只用过@GET、@POST。
@OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
3.RESTEasy @path 与正则表达式映射 如果你解决了跨域问题,可以通过这个,让一组资源用一个方法处理options请求

原理

使用的是跨域资源共享 CORS方法,这也是服务器会发送OPTIONS预请求的基础。
因为restful每个方法都指定了请求类型是GET还是post,所以如果浏览器发送了一个OPTIONS类型的请求,原来的方法实际上是没有进入(因为类型不匹配)。比如你的请求为get请求’ 192.168.0.111:8080/aaa/bbb?a=1&b=2’,实际上**预请求**OPTIONS也是访问的这个链接,只不过类型不匹配没有进入。
所有我们需要一个新的方法来专门处理OPTIONS请求。

解决方法

具体方法如下:

    /**
     * 进行跨域请求的配置
     * @param response
     * @param httpRequest
     * @return
     */
    @OPTIONS
    @Path("/bbb")
    public Response MysqlConnectionTester(@Context HttpServletResponse response,@Context HttpServletRequest httpRequest) {
        log.info("-----------------进行跨域请求的配置进入-----------------");//日志打印
//        String origin = httpRequest.getHeader("Origin"); //获取跨域连接
        response.addHeader("Access-Control-Allow-Origin", "*");//允许所有域名的脚本访问该资源。
        response.addHeader("ccess-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.addHeader("Content-Type", "text/html; charset=utf-8");
        response.addHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");  
        return Response.status(200).build();
    }

    /**
     * 实际请求方法
     * @param response
     * @return
     */
    @GET
    @Path("/bbb")
    public Response discountActive(@Context HttpServletResponse response) {
        JSONObject ret = new JSONObject();
        ret.put("code", "500");
        ret.put("message", "数据查询完毕");
        return ResponseBuilder.error(ret.toString());
    }

上述请求的链接相同,但是请求类型不同。
这样就可以了,OPTIONS的发送和接收都是浏览器的行为,与你项目是无关的,所以前端是不需要修改的,只需要让服务器能正确把OPTIONS的结果发送出去。

解决完成后OPTIONS响应头内容:

Access-Control-Allow-Headers    :Origin, No-Cache, X-Requested-Type, X-E4M-With,userId,token
Access-Control-Allow-Methods    :POST, GET, OPTIONS, DELETE
Access-Control-Allow-Origin :*
ccess-Control-Allow-Credentials :true
Content-Length  :0
Content-Type    :text/html;charset=utf-8
Date    :Fri, 18 May 2018 07:50:14 GMT
Server  :Apache-Coyote/1.1

多出来Access-Control的内容。

扩展

让一组资源链接的OPTIONS预请求使用一个方法处理:

    /**
     * 进行跨域请求的配置
     * @param response
     * @param httpRequest
     * @return
     */
    @OPTIONS
    @Path("/{var}")
    public Response MysqlConnectionTester(@Context HttpServletResponse response,@Context HttpServletRequest httpRequest) {
        log.info("-----------------进行跨域请求的配置进入-----------------");//日志打印
//        String origin = httpRequest.getHeader("Origin"); //获取跨域连接
        response.addHeader("Access-Control-Allow-Origin", "*");//允许所有域名的脚本访问该资源。
        response.addHeader("ccess-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.addHeader("Content-Type", "text/html; charset=utf-8");
        response.addHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");  
        return Response.status(200).build();
    }

原理使用Path通配符,具体原理见参考文档 [3] (在上面)。

2018-05-18创建

猜你喜欢

转载自blog.csdn.net/u013494765/article/details/80367148