angularjs跨域请求,html5封装进android与ios

前端之家收集整理的这篇文章主要介绍了angularjs跨域请求,html5封装进android与ios前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

前言

第一次正儿八经的写博客实在有点不知道怎么开头好,所学的东西也不够系统,我相信我写的东西瞄准了一个点去写,无论从哪里开始,都会让人觉得有点突然,但是,我也没办法从所谈主题的起源开始谈,所以不纠结这个次序关系了,有关主题的前后我就稍微介绍一些,主要围绕我所遇到的问题和如何去解决来谈吧。

我使用的框架是springboot+angularjs内容主要包括
- 为什么需要跨域
- js跨域请求
- 使用localStorage替代本地Cookies
- 使用token替代跨域发送Cookies

下面主要针对以上几点来分别说说


为什么需要跨域

我们这个俄项目是使用springboot+angularjs开发的,web端顺利开发结束,接下来是手机端,手机端直接使用html在电脑端运行也开发的比较顺利,因为是直接使用的PC端浏览器,所以和web端开发是没有区别的,当然,手机端的浏览器也同样不会有什么问题。但是我们公司项目能打包成android和ios的app,android和ios都支持webview,按理直接把url告诉webview然后去请求服务器访问也没什么问题,毕竟通过webview的形式,理论上就相当于使用了android和ios提供的一个浏览器而已,只是它隐藏了url。
考虑到手机上的切换效果,app开发的同事会使用多个webview来切换渲染数据,像详情之类的页面,需要开启新的webview,这样问题就来了,体验就非常的差了,非常的卡!非常的慢!为什么?

我简单的做了个比较.

Web端打开新页面过程

App端打开新页面过程

过程比较:

过程 web app
第一次加载
切换页面

由此可见,使用android或ios嵌套webview来达到一般原生的切换效果和访问服务器的速度,是很难的!

此时我们想到三个方案:

  1. app端只开启一个webview。

    • 优点:可以减少切换页面时重新开启(特定的导航页面在切换时没有被关闭掉,但不刷新)webview的时间。
    • 缺点:b)页面效果可能较差,并且ios打包后有可能影响appstore审核。
  2. 服务器端后台文件和前端文件分开部署。

    • 优点:稍微加快静态页面访问速度。
    • 缺点:提升速度不明显。
  3. html文件本地化,打包进app文件中。

    • 优点:不需要从服务器端请求html再返回到webview中加载,节省了加载html的时间,速度将有较大提升。
    • 缺点:需要对当前项目做很多修改文件访问路径方面,后续webview对接也给我们带来了许多困难)

虽然是想到了三个可行方案,但第一种方案直接被pass,第二种方案速度提升非常不明显,那只能考虑采用第三种了,将原先html文件与java文件共同打包成一个war包,然后现在需要将html文件直接打包进app文件,必然就需要js进行跨域请求了。

JS跨域请求

s跨域请求需要在js和服务器端都有申明跨域,具体如下:

  • 原生ajax 请求可以这样写:
$.ajax({
            type: 'POST',url: "/user",data: {
                'phone': 'xxxxxxxx','password':'xxxxxxx'
            },withCredentials: true,// 跨域
            dataType: 'json'
        }).success(function(){

        });
  • angularjs
$http.get(url,{ 
            withCredentials : true    //跨域
});
@Component
public class CorsFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException,IOException {
        response.setHeader("Access-Control-Allow-Origin",request.getHeader("origin"));   //允许跨域
        response.setHeader("Access-Control-Allow-Credentials","true");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setHeader("Access-Control-Allow-Methods","POST,GET,PUT,OPTIONS,DELETE");
            response.setHeader("Access-Control-Max-Age","3600");
            response.setHeader("Access-Control-Allow-Headers","Origin,X-Requested-With,Content-Type,Accept,Authorization");
        }
        filterChain.doFilter(request,response);
    }
}
response.setHeader("Access-Control-Allow-Origin",request.getHeader("origin"));

这行代码是有点意思的,我这里没有将值直接设为“*”号,将值设为星号无法跨域发送cookies,需要发送cookies的可以设置成

request.getHeader("origin");

这样跨域发送请求就没有问题了。

使用localStorage替代本地Cookies

跨域后有个问题真的让我头疼了很久,虽然成功跨域了,数据也都已经成功返回并渲染页面了。但依然有几个问题。

比如,登录成功后session在后台保存了用户会话信息,再次发送请求获取数据时,再次读取session验证用户身份时,始终无法取到登录时存储的会话信息,因为没有获取到cookies,而服务器与浏览器之间的会话sessionID是保存在cookies中的,为什么没有获取到cookies,是因为服务器端允许跨域是这样设置的:

response.setHeader("Access-Control-Allow-Origin","*");   //允许跨域

origin设置成“*”,是不支持文件形式的访问所发送cookies的,需要怎么改呢?改成与本地文件一样的路径形式就成,比如,在我的机器上如果html路径是 file:///D:test.html,我在java端允许跨域就必须设置成

response.setHeader("Access-Control-Allow-Origin","file://");   //允许跨域 

才能获取到cookies,考虑到html打包进ios或android app中的路径可能不同,则将路径设为:

response.setHeader("Access-Control-Allow-Origin",request.getHeader("origin"));

这点可让我找了很久,“*”居然不行,我到现在也没想通。

  • 本地cookies保存

登录的问题解决了,发送cookies也没有问题了,但是本地文件的cookies保存又出了问题,无法保存!也许有办法只是我没找到。

考虑到不同浏览器之间的差别和ios对cookies的可能支持不太好的问题,决定打算使用用localStorage在本地文件保存一些信息,因为localStorage是html5自带的,不存在不同浏览器之间的差别。
localStorage的使用也比较简单,我在这个项目中也只使用了几个方法

首先申明一个全局的storage,因为本身用他的目的就是替代cookies保存用户状态,当然是全局的啦

var storage = window.localStorage;

然后保存值

storage.setItem('userid','深蓝浅蓝的天')

取值

storage.getItem('userid');

退出清空storage

storage.clear();

so easy,我很快就搜索全部代码将cookies的使用全部替换掉了(注意搜索路径哦),但是问题到了这里还是没有结束,在电脑上测试完了本地文件的访问都没有了问题,但是用android或ios打包html文件又出现问题了。

post方法可正常跨域,因为它的headers中的origin是有指的,而get方法origin却是是null,而服务器端对于null是不接收跨域发送cookies,所以cookies还是要忍痛替换掉。++

使用token替代跨域发送Cookies

cookies既然有那么多的问题,而且可能在某些地方支持不太好,之后若是需要对app进行功能扩展,第三方授权之类的,也还是要走token,所以索性直接换掉cookies,当然,我在js中是有区分web/ios/android的,所以手机浏览器端仍然延续使用cookies,ios和android打包文件形式则用token。

虽然在服务器代码中session几乎无处不在,但要替换成token也不会特别麻烦,将原先保存在session中的数据,使用token作为一个键保存在redis中,然后在用户请求服务器时,拦截请求并取出token,再从redis中取出数据手动赋值到session中就可以了,只是我把原先服务器接收请求并取出cookies中sessionID,从而取出对应session的动作替换了下而已。

简单图示就是:
- 服务器处理cookies

第一次请求服务器

第二次请求服务器

大致过程如上图,用markdown不会画图,下次画个好点的~~

  • token替换cookie
    第一次请求服务器

    第二次请求服务器

过程几乎是一样的,只是我在拦截中做了一步处理,以便我不需要大幅度改变原有代码,如下:

@Override
public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
        HttpSession session = request.getSession();
        if (session.getAttribute("userId") == null) {
            String token = request.getHeader("Authorization");
            if (token != null && !token.equals("null")) {
                String jsonToken = (String) redisTemplate.opsForValue().get(token);
                UserToken userToken = JSON.parSEObject(jsonToken,UserToken.class);
                if (userToken != null) {
                    session.setAttribute("userId",userToken.getUserId());
                }
            }
        }
        return true;
    }

过程大致如此。

第一次写这么长的博文,欢迎指正。

猜你在找的Angularjs相关文章