• ajax的跨域解决方案(java+ajax)


    简单的建立一个后台项目

    新建servlet:

    内容如下:

    package a;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class TestServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
          System.out.println("执行了一个跨域请求"); response.setContentType(
    "text/plain;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("success"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

    web.xml

    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>a.TestServlet</servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/s/t</url-pattern>
      </servlet-mapping>

    前端代码:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title></title>
        </head>
        <body>
            <button onclick="goAjax()">ajax</button>
        </body>
        <script type="text/javascript" src="js/jquery-2.1.4.js" ></script>
        <script type="text/javascript">
            function goAjax(){
                $.ajax({
                    url:"http://192.168.0.102:8080/a/s/t",
                    type:"get",
                    success:function(data){
                        console.log(data);
                    }
                });
            }
        </script>
    </html>

    运行前后台项目,出现异常情况

    在查看ajax的发送情况

    从这里可以看到结果是正确返回的;并且后台也是正常执行了。

    因此得出结论:

    跨域是浏览器在aja返回结果的时候进行了拦截,先执行,后判断,不是后台不允许跨域;

    客户端建立一条img标签,地址是刚才的ajax地址

    <img src="http://192.168.0.102:8080/a/s/t" />

    查看请求

    查看请求,依然是成功的。

    结论:跨域只发生在xmlHttpRequest对象上,通俗点说就是发生在ajax上。

    浏览器从我们的请求路径中解析出我们的ajax请求的主机信息,得知是跨域请求,就会给请求头添加一个origin头信息。

    我们可以在返回的时候添加一个响应头,来通过浏览器对跨域拦截。

    1.通过修改后台代码实现跨域

    添加过滤器CrossFilter.java

    package a;
    
    import java.io.IOException;
    
    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.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class CrossFilter implements Filter{
        @Override
        public void destroy() {}
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res,
                FilterChain doChain) throws IOException, ServletException {
            HttpServletRequest request=(HttpServletRequest) req;
            HttpServletResponse response=(HttpServletResponse)res;
            request.setCharacterEncoding("utf-8");
            //response.setContentType("text/plain;charset=utf-8");
            //response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8020");或者
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "*");//GET  POST
            //response.setHeader("Access-Control-Allow-Headers","content-type");
            //跨域预检缓存
            response.setHeader("Access-Control-Max-Age","3600");
            doChain.doFilter(req,res);
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
            
        }
    
    }

    web.xml

    <filter>
            <filter-name>CrossFilter</filter-name>
            <filter-class>a.CrossFilter</filter-class>
        </filter>
        <filter-mapping>
             <filter-name>CrossFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

    现在已经可以实现跨域请求了。

    简单请求:

      1.get,head,post

      2.请求header里面

        1)无自定义头

        2)Content-Type为以下几种:text/plain,multipart/form-data,application/x-www-form-urlencoded.

    非简单请求

      1.put,delete方法的ajax请求

      2.发送json字符串格式的ajax请求

      3.带自定义头的ajax请求

    ajax发送非简单请求的时候,会出现请求不通的情况

    $.ajax({
                    url:"http://192.168.0.102:8080/a/s/t",
                    type:"post",
                    contentType:"application/json",
                    data:JSON.stringify({name:"gys"}),
                    success:function(data){
                        console.log(data);
                    }
                });

    结合上面的提示我们给过滤器添加一条头部信息。

    重新运行,跨域问题解决,查看请求的时候发现,一个ajax请求发送了两边。

    第一条是一条预检请求,这个请求是在发生非简单请求时,检查跨域请求是否能被通过。

    如果每次请求都这样预检一次,会非常耗费网络资源,影响我们的请求速度。

    可以在过滤器端添加一个预检缓存。

    现在只有第一次请求的时候会出现预检请求,后面的就没有了。

    可是我现在想要恢复预检请求,把预检代码注释了,可是还没到预检请求的缓存时间,同样没有办法查看到预检请求。

    可以勾选谷歌浏览器的Disable cache

    带cookie的ajax请求

    jquery的ajax请求,指定带上cookie信息的参数是:xhrFields

    function goAjax(){
                $.ajax({
                    url:"http://192.168.0.102:8080/a/s/t",
                    type:"post",
                    xhrFields:{
                        withCredentials:true  //发送ajajx请求的时候会带上cookie
                    },
                    success:function(data){
                        console.log(data);
                    }
                });
            }

    请求结果:

    这个时候的请求是不通的,根据提示我们修改后台java代码。

    因为带有cookie信息后,浏览器就会对响应的请求做校验,这个时候*号就不好使了;

    改成这样

    再次请求;结果如下

    根据提示添加响应头

    再次请求,这个时候就访问通了。

    根据以上的写法,只能有一个客户端可以进行跨域访问,如果127.0.0.1改成localhost访问就不通了,现在想要任何方向都能够实现跨域请求,并且带cookie.

    @Override
        public void doFilter(ServletRequest req, ServletResponse res,
                FilterChain doChain) throws IOException, ServletException {
            HttpServletRequest request=(HttpServletRequest) req;
            HttpServletResponse response=(HttpServletResponse)res;
            
            String origin=request.getHeader("Origin");
            if(origin!=null && !"".equals(origin)){
                response.setHeader("Access-Control-Allow-Origin", origin);
            }
            //request.setCharacterEncoding("utf-8");
            //response.setContentType("text/plain;charset=utf-8");
            //response.setHeader("Access-Control-Allow-Origin","http://127.0.0.1:8020");
            //或者
            //response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "*");//GET  POST
            response.setHeader("Access-Control-Allow-Headers","content-type");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            //跨域预检缓存
            //response.setHeader("Access-Control-Max-Age","3600");
            doChain.doFilter(req,res);
        }

    现在在前端改成localhost访问 依然可以访问通。

    nginx的转发,实现跨域(原理就是将上面过滤器中的内容配置到nginx中,并且上面的过滤器可以干掉了。)

    为了便于演示,使用windows版的nginx,不用安装;nginx什么版本不重要。

    在C:WindowsSystem32driversetc中修改hosts文件

    修改配置文件  conf中的nginx.conf

    在nginx.conf同级中新建vhost文件夹

    添加b.com.conf文件,内容如下

    server{
        listen 80;
        server_name b.com;
    
        location /{
            proxy_pass http://localhost:8080/;
        }
    }

    然后使用命令行测试我们的配置文件

    表明测试成功。

    把我们的后台项目跑起来,浏览器地址栏输入

    b.com/a.如果界面是你的后台项目提供的界面,说明nginx代理成功了。

    继续修改b.com.conf配置文件。

    server{
        listen 80;
        server_name b.com;
    
        location /{
            proxy_pass http://127.0.0.1:8080/;
    
            add_header Access-Control-Allow-Methods *;
            add_header Access-Control-Max-Age 3600;
            add_header Access-Control-Allow-Origin $http_origin;
            add_header Access-Control-Allow-Headers $http_access_control_request_headers;
    
            if ($request_method = OPTIONS){
                return 200;
            }
        }
    }

    测试配置文件是否通过

    nginx.exe -t

    重新载入nginx配置文件

    nginx.exe -s reload

    修改前端的ajax方法的路径

    function goAjax(){
                $.ajax({
                    url:"http://b.com/a/s/t", //"http://192.168.0.102:8080/a/s/t",
                    type:"post",
                    success:function(data){
                        console.log(data);
                    }
                });
            }

    好,完美实现通过配置nginx添加跨域响应头。

    nginx的配置反向代理,实现跨域

     修改host文件

    在nginx中vhost添加a.com.conf文件,内容如下:

    server{
        listen 80;
        server_name a.com;
    
        location /{
            proxy_pass http://127.0.0.1:8020/;
        }
    
        location /ajaxserver{
            proxy_pass http://127.0.0.1:8080/a/;
        }
    }

    配置文件意思是这样的:

    访问a.com/a/index.html时,niginx代理会跳转到前端项目127.0.0.1:8020/a/index.html

    页面中的跨域请求通过访问/ajaxserver/t/s时,nginx会把请求转发到后台项目中,地址是127.0.0.1:8080/a/t/s;

    检测配置文件,然后重新载入

    nginx.exe -t
    nginx.exe -s reload

    好,跨域请求全部结束了。

    慕课网笔记,老师讲的很好。

  • 相关阅读:
    PTA(Basic Level)1038.统计同成绩学生
    PTA(Basic Level)1026.程序运行时间
    PTA(Basic Level)1031.查验身份证
    PTA(Basic Level)1061.判断题
    Windows 常用命令
    Windows安装启动MySQL
    classpath路径配置
    IDEA远程调试
    Java Effective 读书笔记
    Try Catch Finally总结
  • 原文地址:https://www.cnblogs.com/guoyansi19900907/p/8949348.html
Copyright © 2020-2023  润新知