资讯专栏INFORMATION COLUMN

IE9下的跨域问题小总结

Jokcy / 476人阅读

摘要:由于浏览器同源策略,凡是发送请求的协议域名端口三者之间任意一与当前页面地址不同即为跨域最近项目要兼容,找了一些资料,实践了一下,现在总结一下,避免以后踩坑。解决方案,微软在和下给我们提供了来进行解决跨域问题,官方的文档可以在这里看到。

由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域

最近项目要兼容IE9,找了一些资料,实践了一下,现在总结一下,避免以后踩坑。

普通请求的跨域 简单粗暴的解决方案

第一次碰到这个问题,所以就是上网找找有没有什么好的解决方案。最初找到的方案是这样的,直接在IE中设置设置受信任的站点,然后允许其可以进行跨域访问,最后在jQuery中设置开启跨域请求。oh,No!这么粗暴,好吧,这也是一个不是办法的办法,如果做的是一个小项目,用户不多,那直接写在用户手册里,让他们自己去配吧。但是,这显然不是一个好的解决方案啊,那只能继续找了。

XDomainRequest(XDR)解决方案

ok,微软在IE8IE9下给我们提供了XDomainRequest来进行解决跨域问题,官方的文档可以在 这里看到。当然Github上也有开源的jQuery插件,可以在这里找到。

XDR的限制:

XDR仅支持GETPOST这两种请求方式,虽然可以使用上面提交的插件来解决前端部分只要进行简单修改代码就可以提交PUT/HEAD/DELETE的请求的问题,但是其请求的发生出去依旧还是将PUT/HEAD/DELETE转化为POST,将HEAD 转化为GET请求。当是POST请求的时候,请求方案会以__method=原请求的方式结构加入到请求体的body中。当是HEAD 请求的时候,请求方案会以__method=原请求的方式结构加入请求url的查询参数中。现在大部分API开发都是按照RESTful规范进行设计的,如果是自己的服务端还好,可以叫服务端的同学添加一个拦截器做一个拦截判断,然后执行对应的方法(ps:我想过去应该是这个样子,不知道服务端的同学会不会磨刀子)。但是如果你调用是网上的API的接口的话,那就爱莫能助了。

XDR不支持自定义的请求头,因此如果你的服务端是用过header中的自定义参数进行做身份验证的话,那也行不通了。

请求头的Content-Type只允许设置为text/plain

XDR不允许跨协议的请求,如果你的网页是在HTTP协议下,那么你只能请求HTTP协议下的接口,不能访问HTTPS 下的接口。

XDR只接受HTTP/HTTPS 的请求

发起请求的时候,不会携带authentication cookies

JSONP

JSONP的本质是动态的加载

然后自己定义一个上传的组件,我这里是使用Vue来包装成一个组件的



这个插件是依赖jQuery的,并且依赖jQuery-UI ,还有要注意的是在IE10以下的版本都要引入jquery.iframe-transport

jquery.xdr-transport

我代码中发送数据的方式是它在add 方法中返回的data数据,通过该对象去直接上传文件,这时上传的FormData的文件信息中,文件原本是什么类型就是什么类型了,这是我们所期望的。我之前查看官方的文档,还使用过另一种方式

var jqXHR = $("#fileupload").fileupload("send", {files: filesList})
    .success(function (result, textStatus, jqXHR) {/* ... */})
    .error(function (jqXHR, textStatus, errorThrown) {/* ... */})
    .complete(function (result, textStatus, jqXHR) {/* ... */});

上传的时候使用的是这样的方式,发现FormData中上传文件的类型变为了Content-Type: application/octet-stream,然后服务器就解析不到数据了。所以还是推荐用它原生的submit方式去提交数据。

注意

这两个插件的本质还是使用form表单上传文件,因此我们无法添加自定义的header头,并且如果原来的服务器不支持请求重定向的话怎么办,那就没有办法使用jQuery-File-Upload这个插件了。所以最稳妥的方式,还是在我们本地做了一层代理,由代理去发生真正的请求。

下面给出主要的转发FormDatajava代码

public ResponseEntity dispatcherUpload(HttpServletRequest request) throws UnsupportedEncodingException {

    String requestUrl = request.getParameter("request_url");
    String redirectUrl = request.getParameter("redirect");
    String fileName = request.getParameter("name");

    if (StringUtils.isEmpty(requestUrl) || StringUtils.isEmpty(redirectUrl))
      throw new BizException(ErrorCode.INVALID_ARGUMENT);

    HttpClient httpClient = new DefaultHttpClient();
    HttpPost httpPost = new HttpPost(requestUrl);
    String auth = request.getParameter("authorization");
    if (!StringUtils.isEmpty(auth))
      httpPost.addHeader("Authorization", request.getParameter("authorization").toString());
    MultipartEntity reqEntity = new MultipartEntity();

    if (!StringUtils.isEmpty(request.getParameter("path"))) {
      StringBody pathBody = new StringBody(request.getParameter("path"));
      reqEntity.addPart("path", pathBody);
    }
    if (!StringUtils.isEmpty(request.getParameter("scope"))) {
      StringBody scopeBody = new StringBody(request.getParameter("scope"));
      reqEntity.addPart("scope", scopeBody);
    }
    if (!StringUtils.isEmpty(request.getParameter("expireDays"))) {
      StringBody expireDaysBody = new StringBody(request.getParameter("expireDays"));
      reqEntity.addPart("expireDays", expireDaysBody);
    }
    if (!StringUtils.isEmpty(fileName)) {
      StringBody nameBody = new StringBody(fileName);
      reqEntity.addPart("name", nameBody);
    }

    MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
    MultiValueMap multiValueMap = multipartHttpServletRequest.getMultiFileMap();
    //todo:现在暂时写死,不去遍历map
    if(!(multiValueMap.containsKey(CS_FILE_KEY) || multiValueMap.containsKey(UC_FILE_KEY)))
      throw new BizException(ErrorCode.INVALID_ARGUMENT);
    String fileKey = multiValueMap.containsKey(CS_FILE_KEY) ? CS_FILE_KEY : UC_FILE_KEY;
    MultipartFile multipartFile = multipartHttpServletRequest.getFile(fileKey); // 得到文件数据
    if (!multipartFile.isEmpty()) {

      CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile) multipartFile;
      DiskFileItem diskFileItem = (DiskFileItem) commonsMultipartFile.getFileItem();
      String filePath = diskFileItem.getStoreLocation().getPath().toString();

      File file = null;
      try {
        //判断目录是否已存在,如果filename不为空,将其带入创建文件(真实还原文件类型,否则是.tmp临时文件)
        if (StringUtils.isEmpty(fileName)) {
          file = new File(filePath);
        } else {
          file = new File(filePath, fileName);
        }
        if (!file.exists()) {
          file.mkdirs();
        }
        //保存文件
        multipartFile.transferTo(file);
        FileBody bin = new FileBody(file);
        reqEntity.addPart(fileKey, bin);
        httpPost.setEntity(reqEntity);

        HttpHeaders responseHeader = new HttpHeaders();
        HttpResponse httpResponse = null;
        try {
          httpResponse = httpClient.execute(httpPost);
        } catch (Exception e) {
          LOG.error("代理文件上传失败,请求地址:{},请求内容:{}", requestUrl, null, e);
          JSONObject failedJson = new JSONObject();
          failedJson.put("result", "FAILURE");
          failedJson.put("data", e.toString());
          URI uri = URI.create(redirectUrl + e.toString());
          responseHeader.setLocation(uri);
          return new ResponseEntity(responseHeader, HttpStatus.MOVED_TEMPORARILY);
        }
        LOG.info("状态码:" + httpResponse.getStatusLine().getStatusCode());
        org.apache.http.HttpEntity httpEntity = httpResponse.getEntity();
        //判断请求是否成功
        String responseBody = "";
        String isSuccess = "SUCCESS";
        if (httpResponse.getStatusLine().getStatusCode() >= HttpStatus.OK.value() && httpResponse.getStatusLine().getStatusCode() < HttpStatus.BAD_REQUEST.value()) {
          if (null != httpEntity) {
//            System.out.println("响应内容:" + EntityUtils.toString(httpEntity, ContentType.getOrDefault(httpEntity).getCharset()));
            responseBody = EntityUtils.toString(httpEntity, ContentType.getOrDefault(httpEntity).getCharset());
            //处于安全考虑,关闭数据流
            EntityUtils.consume(httpEntity);
          }
        } else {
          //上传失败(非2XX)
          isSuccess = "FAILURE";
        }
        JSONObject ResJson = new JSONObject();
        ResJson.put("result", isSuccess);
        ResJson.put("data", responseBody);
        URI uri = URI.create(redirectUrl + URLEncoder.encode(ResJson.toString(), "UTF-8"));
        responseHeader.setLocation(uri);
        return new ResponseEntity(responseHeader, HttpStatus.MOVED_TEMPORARILY);
      } catch (IOException e) {
        throw new BizException(ErrorCode.INTERNAL_SERVER_ERROR, e);
      } finally {
        if (file != null) {
          file.delete();
        }
      }
    }else {
      throw new BizException(HttpStatus.BAD_REQUEST, "PORTAL-APP/INVALID_ARGUMENT", "上传文件为空");
    }
  }

在转发文件的时候,我们做了一层转存,原因在于,我们测试一个服务器的时候,我们直接使用一个缓存的数据,去写到FormData中,那边服务器接收到的文件对象居然是空的,因此我们才做了一层缓存,用一个真实存在的文件去做。

---end---

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86953.html

相关文章

  • Vue 兼容 ie9 的全面解决方案

    摘要:本文将针对使用生态开发完成的网站,以版本为基础兼容目标,实现全功能正常使用的全面兼容解决方案。这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。此外,使用这个,一旦页面不处于浏览器的当前标签,就会自动停止刷新。 前言 背景情况 vue - 2.5.11 vue-cli 使用模板 webpack-simple http请求:axios Vue 官方对于 ie 浏览器版本兼容情...

    codeKK 评论0 收藏0
  • Web开发之跨域跨域资源共享

    摘要:例外当涉及到同源策略时,有两个主要的例外授信范围两个相互之间高度互信的域名,如公司域名,不遵守同源策略的限制。端口未将端口号加入到同源策略的组成部分之中,因此和属于同源并且不受任何限制。 原文链接:http://www.devsai.com/2016/11/24/talk-CORS/ 同源策略(same origin policy) 1995年,同源政策由 Netscape 公司引入浏...

    Eastboat 评论0 收藏0
  • web安全一,同源策略与跨域

    摘要:可以说同源策略在安全中扮演着及其重要的角色。我把这个领域的东西写成了一个系列,以后还会继续完善下去安全一同源策略与跨域安全二攻击安全三攻击 之所以要将同源策略与跨域写在一起,是因为存在浏览器的同源策略,才会存在跨域问题 何为同源策略 同源策略是浏览器实现的一种安全策略,它限制了不同源之间的文档和脚本交互的权限。只有同一个源的脚本才会具有操作dom、读写cookie、session 、a...

    cgspine 评论0 收藏0
  • 前端跨域方法论

    摘要:说明是否允许通讯同一域名允许同一域名下的不同文件夹允许不同端口号不允许不同协议不允许不同域名不允许主域相同,子域不同不允许跨域解决方案由于浏览器同源策略是允许标签这样的跨域资源嵌套的,所以标签的资源不受同源策略的限制。 前言 本着学习和总结的态度写的技术输出,文中有任何错误和问题,请大家指出。更多的技术输出可以查看我的 github博客。 整理了一些前端的学习资源,希望能够帮助到有需要...

    leejan97 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<