React Native Cookie使用指南

作者: ronniegong | 来源:发表于2016-11-19 18:31 被阅读6739次

    React Native Cookie使用指南

    web开发中,cookie是一个常用工具。通常会将用户与服务器会话的sessionid存储在cookie中,用以在请求中标示会话来源。或者将登录态token值存储在cookie中,请求中通过cookie值校验登录态。

    当我们使用react native开发应用时,是否还能像在web开发中那样使用cookie呢?官方文档中没有相关资料,需要我们自己去探索。

    场景探索

    本文采用react native 0.35版本,针对以下场景进行了探索

    • 1.访问接口A返回的cookie值,在后续访问接口B时,是否会带上?

      在react native中,使用fetch api访问后台接口。访问同一站点,接口A返回的cookie值,在继续范围该站点接口B时,通过抓包工具可以观察到,cookie在请求中会被带上

      ios和android均验证有效

    • 2.在react native应用中登录后,登录态如何传递给webview中第三方业务的页面?

      在web开发中,调用登录接口后,返回结果会在cookie中设置token值。当从这一页面进入其他第三方业务的页面时,在各页面主域名一致,均和cookie中token值的域名匹配时,打开第三方业务页面,会直接将带有token的cookie值设置在请求头中,从而实现登录态的共享。

      在react native应用中,沿用web端登录接口。当使用fetch api调用登录接口login后,接口返回头中设置cookie token,域名.main.com。从react native应用通过webview打开url 为b.main.com第三方页面时,因为主域名一致,均与cookie中token域名匹配,此时打开页面的请求中,也会自动带上含有token的cookie,从而实现登录态的共享。

      ios和android均验证有效

    • 3.登录后,关闭应用再次进入,登录态是否保持?

      登录应用后,采用杀进程方式关闭应用。再次打开应用,期望登录态依然保持,实际效果如何?

      如果登录接口返回cookie时,为cookie值设置了过期时间,且过期时间在当前时间之后,即未过期。则再次进入应用,cookie值仍然保持。ios和android均验证有效

      如果登录接口返回cookie时,cookie值没有设置过期时间,或者设置了一个在当前时间之前的时间。则再次进入应用时,ios端cookie值丢失,android端仍保持

      因此,为了在再次进入应用时,仍然保持登录态。登录接口设置cookie token时,需要设置一个相对较久的过期时间。

    • 4.可否为请求主动设置cookie?

      假如在集成react native的原生应用中,原生应用完成登录。由原生应用进入react native应用时,通过变量传递方式传递一个token值。这时在react native应用接口及通过webview加装第三方业务时,怎么共享由原生端传递的登录态?

      这种场景相当于本身没有cookie,需要在react native中主动为请求设置cookie,将token值设置到请求头中,以此来实现登录态的传递。

      社区中已经有相应方法,可以查阅react-native-cookies
      或者react-native-cookiemanager

    原理分析

    上述场景中可见,react native对cookie支持度还是很高的。那么这个支持是如何实现的呢?带着这个问题,笔者阅读了react-native-cookiemanager的源码。

    笔者没有原生客户端开发经验,是通过阅读代码,发现实际在客户端,android和ios各有原生api支持对cookie的操作。并且,通过查阅资料,了解到安卓和ios端,分别会将cookie以文件形式持久化,这也是为什么再次进入应用中,仍然能获取到cookie值的原因。

    react-native-cookiemanager安卓端关键代码

    @ReactMethod
        public void setCookie(ReadableMap options) {
            String name = null;
            String value = null;
            String domain = null;
            String origin = null;
            String path = null;
            String expiration = null;
            if (options.hasKey(OPTIONS_NAME)) {
                name = options.getString(OPTIONS_NAME);
            }
            if (options.hasKey(OPTIONS_VALUE)) {
                value = options.getString(OPTIONS_VALUE);
            }
            if (options.hasKey(OPTIONS_DOMAIN)) {
                domain = options.getString(OPTIONS_DOMAIN);
            }
            if (options.hasKey(OPTIONS_ORIGIN)) {
                origin = options.getString(OPTIONS_ORIGIN);
            }
            if (options.hasKey(OPTIONS_PATH)) {
                path = options.getString(OPTIONS_PATH);
            }
            if (options.hasKey(OPTIONS_EXPIRATION)) {
                expiration = options.getString(OPTIONS_EXPIRATION);
            }
            CookieManager.getInstance().setCookie(origin, name + "=" + value + ";"
                    + OPTIONS_PATH + "=" + path + ";"
                    + OPTIONS_EXPIRATION + "=" + expiration + ";"
                    + OPTIONS_DOMAIN + "=" + domain);
        }
    
        /**
         * Gets the cookies for the given URL.
         *
         * @param url the URL for which the cookies are requested
         * @return value the cookies as a string, using the format of the 'Cookie'
         * HTTP request header
         */
        @ReactMethod
        public void getCookie(String url, Callback callback) {
            String cookie = CookieManager.getInstance().getCookie(url);
            callback.invoke(cookie);
        }
    
        @ReactMethod
        public void removeAllCookies() {
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
                    @Override
                    public void onReceiveValue(Boolean value) {
                    }
                });
            } else {
                CookieManager.getInstance().removeAllCookie();
            }
        }
    

    react-native-cookiemanager ios端关键代码

    RCT_EXPORT_METHOD(setCookie:(NSDictionary *)props) {
        NSString *name = [RCTConvert NSString:props[@"name"]];
        NSString *value = [RCTConvert NSString:props[@"value"]];
        NSString *domain = [RCTConvert NSString:props[@"domain"]];
        NSString *origin = [RCTConvert NSString:props[@"origin"]];
        NSString *path = [RCTConvert NSString:props[@"path"]];
        NSDate *expiration = [RCTConvert NSDate:props[@"expiration"]];
    
        NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
        [cookieProperties setObject:name forKey:NSHTTPCookieName];
        [cookieProperties setObject:value forKey:NSHTTPCookieValue];
        [cookieProperties setObject:domain forKey:NSHTTPCookieDomain];
        [cookieProperties setObject:origin forKey:NSHTTPCookieOriginURL];
        [cookieProperties setObject:path forKey:NSHTTPCookiePath];
        [cookieProperties setObject:expiration forKey:NSHTTPCookieExpires];
    
        NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    }
    
    
    RCT_EXPORT_METHOD(clearAll:(RCTResponseSenderBlock)callback) {
        NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        for (NSHTTPCookie *c in cookieStorage.cookies) {
            [cookieStorage deleteCookie:c];
        }
        callback(@"success");
    }
    
    // TODO: return a better formatted list of cookies per domain
    RCT_EXPORT_METHOD(getAll:(RCTResponseSenderBlock)callback) {
        NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
        NSMutableDictionary *cookies = [NSMutableDictionary dictionary];
        for (NSHTTPCookie *c in cookieStorage.cookies) {
            NSMutableDictionary *d = [NSMutableDictionary dictionary];
            [d setObject:c.value forKey:@"value"];
            [d setObject:c.name forKey:@"name"];
            [d setObject:c.domain forKey:@"domain"];
            [d setObject:c.path forKey:@"path"];
            [cookies setObject:d forKey:c.name];
        }
        callback(@[cookies, @"success"]);
    }
    
    

    最后

    在场景三中有一点笔者是有疑问的,就是当cookie值没有设置过期时间、或者设置一个已经失效的时间时,安卓端也会将这一cookie值持久化,使得再次进入应用中还能获取到。

    按照一般理解,没有设置过期时间时,调用setCookie保存cookie,及将cookie持久化时,应该像ios端一样,将这一cookie值丢弃。但是在跟进调试上述代码时,在CookieManager.getInstance().setCookie处的断点进入到的是一个抽象方法,没有进入到实现中,这一疑问有待进一步研究,欢迎安卓端有经验的朋友指导。

    如果觉得有帮助,可以扫描二维码对我打赏,谢谢

    相关文章

      网友评论

      • 383bcce0c238:android 有个问题:
        安卓原生登录之后点击一个按钮跳转到RN界面=> RN组件请求接口(这个接口是有权限校验的)=> fecth请求设置了 credentials: "include", =>安卓一直需要提示重新登录
        同样的方式:ios没有问题
        3193db502eb8:@心之静云则淡 我已经解决,要在rn请求里手动设置cookie,然后卸载程序,在重新安装一次,就行了,不过会有个问题,就是过一天这样子,后台又不认cookie,即使你把本地cookie清除了还是不行,又要重新安装app才行。
        383bcce0c238:没有解决
        3193db502eb8:兄弟,你解决了么,我也卡在这个问题里
      • 鹏雨燕:所以请问下,rn怎么给ios设置cookie
        鹏雨燕:@鹏雨燕 通过原生设置cookie的时效和是否删除属性
        鹏雨燕:@心之静云则淡 解决了
        383bcce0c238:你好,你的解决没有
      • 全端玩法:在使用的时候报错,显示index.ios.bundle?platform=ios&dev=true&minify=false:20437 Add RNCookieMangerIOS.h and RNCookieManagerIOS.m to your Xcode project
      • lesliefang:怎么删除 cookie
        鹏雨燕:cookie man ne rge r

      本文标题:React Native Cookie使用指南

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