美文网首页
浏览器跨域问题,教你手写实现jsonp跨域

浏览器跨域问题,教你手写实现jsonp跨域

作者: 狂澜1991 | 来源:发表于2018-03-21 16:06 被阅读31次

    跨域概述
    为什么会有跨域
    跨域解决办法:1、jsonp;2、后台代理
    手写实现jsonp跨域(包括服务器端代码)

    跨域问题

    A服务器上的页面去获取B服务器上的资源,由于XMLHttpRequest同源策略限制,A页面是获取不到数据的。

    同源:协议、域名、端口号任何一个都要相同,否则就会出现跨域请求。

    为什么会跨域

    为了安全

    解决办法

    方法一:jsonp

    原理:使用script标签可以跨域请求资源的特性,去发送请求,得到数据

    • 核心思想
      动态在页面创建script标签,然后给src设置url,这个url就是跨域请求的链接,然后在页面声明一个方法,这个方法名要和后台返回的数据里带有的名字一样,一般情况下,这个名字是动态设置的,在url中传给后台。
    • 代码示例
      // localhost:9528 服务器 
      // index.html 
      <body>
        <script>
          function getJsonp(data){
            console.log(data)
          }
        </script>
      <script src='http://lcoalhost:9527/getData?call=getJson'></script>
      </body>
    
      // localhost:9527 服务器
      // json/getData 接口 (基于express框架)
      router.get("/getData", function (req, res) {
        res.send("getJson({a:1,b:2,c:3})")
      });
    
    • 效果图


      输出结果
    • 总结
      当script标签去加载 getData?call=getJson 接口时(就当是去请求一个js文件),接口返回数据后,浏览器会去执行得到的数据,这个时候浏览器发现数据是 getJson({a:1,b:2,c:3}) ,那这个getJSON是一个方法呀,所以他会立即执行这个方法,而这个上面我们已经定义好了,所以控制台就打印除了数据,如上图。

    这只是一个简单的实现原理说明,现在有成熟的库可以使用 json ,如果有时间,后期将出关于jsonp框架源码分析的文章。

    • jsonp的缺点:只能解决文本类型的数据跨域,如果是图片呢?那就得需要下面这种方式了。
    方法二:后台代理

    原理:自己搭建一个服务器,提供一个接口,以供前端页面使用,前端页面把url链接发送给后台;然后接到参数后,服务器发送http请求(这儿可以设置各种请求头),接到数据然后返回给页面就行了。

    • 使用场景:在之前写的一个页面,图片路径是用的微信公众号发布的图片,但是在我的项目中请求这些图片,就会出现如下图一样的问题。


      微信公众号图片防盗链

      当然,除了本文要讲的方式之外,还有其他解决办法,比如 iframe 标签,但是图片过多的话,这个方式就不太好了(我的页面里面将全是iframe标签)。我的页面是运行在手机端的,所以还要考虑性能问题,只有把压力交给了服务器。这是效果图,里面图片全是公众号的图片。


      效果图
    • 代码示例
    // 前端代码
    <img src="http://host/micro-site/change?url=http://mmbiz.qpic.cn/mmbiz_jpg/ZHRvtsJlIIyCKYib6WAzImVbYEN9ljaUNIDtUMpAAAdkib2lVjPeUgI8GaNudwez1CUW9sHVLTrRoxzAoAPMicCgw/640?wx_fmt=jpeg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1">
    //  前面 host/micro-site/change 自己服务器的域名和接口
    //  url链接是图片的路径 
    // 服务器接到url后,发送http请求,根据url请求数据,然后返回给前端页面。
    
    // 后端代码 java
        @GetMapping("change")
        public void image(String url, HttpServletResponse response) {
            response.setHeader("Content-Type", "image/*");
            ServletOutputStream outputStream = null;
            try {
                outputStream = response.getOutputStream();
            } catch (IOException e) {
                e.printStackTrace();
            }
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("Referer", "");
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36");
            try {
                CloseableHttpResponse execute = httpClient.execute(httpGet);
                HttpEntity entity = execute.getEntity();
                entity.writeTo(outputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    • 后台代理缺点:这种方式显得有些笨重,多了一层数据请求,本来发送到一个服务器就可以了,现在要通过两台服务器才能返回数据,速度相对慢了一些。

    相关文章

      网友评论

          本文标题:浏览器跨域问题,教你手写实现jsonp跨域

          本文链接:https://www.haomeiwen.com/subject/hdmgqftx.html