美文网首页
Android 接口请求添加cookie和webview中coo

Android 接口请求添加cookie和webview中coo

作者: 全球顶尖伪极客 | 来源:发表于2019-05-15 15:47 被阅读0次

前言

服务端可能需要根据cookie值判定是否有登录、灰度环境、获取相关有效信息等用于区分当前用户。

HttpClient请求添加Cookie

现在大多数项目估计都是使用的okhttp网络请求库,由于这个项目是2015年左右的,当时还是使用的HttpClient封装。
android 6.0(API 23)中,Google已经移除了移除了Apache HttpClient相关的类
推荐使用HttpUrlConnection,如果要继续使用需要Apache HttpClient,需要在eclipselibs里添加org.apache.http.legacy.jarandroid studio里在相应的module下的build.gradle中加入:

android {
useLibrary 'org.apache.http.legacy'
}

HttpClient添加cookie的简单说明

  • 域名:参数中URL域名,一级域名不带path。例如链接https://www.baidu.com/ 需要变换为 www.baidu.com,不能带端口:8080)不带Http(s)://也不待任何后面拼接的连接地址/path,否则无效。

  • 存储方式:CookieStore为接口可自定义,http请求时会构建持续化永久存储cookie相关信息,Cookie 一般是采用SharedPreferences持久化存储、需要的时候读取本地的SharedPreferences后遍历放入ConcurrentHashMap,最终本质为httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    其中ClientContext.COOKIE_STORE="http.cookie-store"

  • 存储cookie一般都需要编码、解码、看是否过期等

使用

Application中的oncreate初始化时就设置cookiestore,如果有自定义可以自己添加后再设置持久性的存储。

    //设置持久化cookieStore
        persistentCookieStore = new PersistentCookieStore(getApplicationContext());
        if (!URLEnvironmentConfig.isForPublish()) {
            persistentCookieStore.addCookie(persistentCookieStore.getCookie("gray_level", "fat", BuildConfig.BuildEnvironmentDomain.split("/")[0]));
        }
        asyncHttpClient.setCookieStore(persistentCookieStore);

   /**
     * 设置cookiestore的本质
     * Sets an optional CookieStore to use when making requests
     * @param cookieStore The CookieStore implementation to use, usually an instance of {@link PersistentCookieStore}
     */
    public void setCookieStore(CookieStore cookieStore) {
        httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    }

image.png
package com.loopj.android.http;
import org.apache.http.client.CookieStore;
/*
    Android Asynchronous Http Client
    Copyright (c) 2011 James Smith <james@loopj.com>
    http://loopj.com

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

package com.loopj.android.http;

import java.util.concurrent.ConcurrentHashMap;

import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.cookie.BasicClientCookie;


/**
 * A persistent cookie store which implements the Apache HttpClient
 * {@link CookieStore} interface. Cookies are stored and will persist on the
 * user's device between application sessions since they are serialized and
 * stored in {@link SharedPreferences}.
 * <p>
 * Instances of this class are designed to be used with
 * {@link AsyncHttpClient#setCookieStore}, but can also be used with a
 * regular old apache HttpClient/HttpContext if you prefer.
 */
public class PersistentCookieStore implements CookieStore {
    private static final String COOKIE_PREFS = "CookiePrefsFile";
    private static final String COOKIE_NAME_STORE = "names";
    private static final String COOKIE_NAME_PREFIX = "cookie_";

    private final ConcurrentHashMap<String, Cookie> cookies;
    private final SharedPreferences cookiePrefs;

    /**
     * Construct a persistent cookie store.
     */
    public PersistentCookieStore(Context context) {
        cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0);
        cookies = new ConcurrentHashMap<String, Cookie>();
        // Load any previously stored cookies into the store
        String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null);
        if (storedCookieNames != null) {
            String[] cookieNames = TextUtils.split(storedCookieNames, ",");
            for (String name : cookieNames) {
                String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null);
                if (encodedCookie != null) {
                    Cookie decodedCookie = decodeCookie(encodedCookie);
                    if (decodedCookie != null) {
                        cookies.put(name, decodedCookie);
                    }
                }
            }

            // Clear out expired cookies
            clearExpired(new Date());
        }
    }

    @Override
    public void addCookie(Cookie cookie) {
        String name = cookie.getName() + cookie.getDomain();
        // Save cookie into local store, or remove if expired
        if (!cookie.isExpired(new Date())) {
            cookies.put(name, cookie);
        } else {
            cookies.remove(name);
        }

        // Save cookie into persistent store
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
        prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
        prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie)));
        prefsWriter.commit();
    }


    @Override
    public void clear() {
        // Clear cookies from persistent store
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
        for (String name : cookies.keySet()) {
            prefsWriter.remove(COOKIE_NAME_PREFIX + name);
        }
        prefsWriter.remove(COOKIE_NAME_STORE);
        prefsWriter.commit();

        // Clear cookies from local store
        cookies.clear();
    }

    @Override
    public boolean clearExpired(Date date) {
        boolean clearedAny = false;
        SharedPreferences.Editor prefsWriter = cookiePrefs.edit();

        for (ConcurrentHashMap.Entry<String, Cookie> entry : cookies.entrySet()) {
            String name = entry.getKey();
            Cookie cookie = entry.getValue();
            if (cookie.isExpired(date)) {
                // Clear cookies from local store
                cookies.remove(name);

                // Clear cookies from persistent store
                prefsWriter.remove(COOKIE_NAME_PREFIX + name);

                // We've cleared at least one
                clearedAny = true;
            }
        }

        // Update names in persistent store
        if (clearedAny) {
            prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet()));
        }
        prefsWriter.commit();

        return clearedAny;
    }

    @Override
    public List<Cookie> getCookies() {
        return new ArrayList<Cookie>(cookies.values());
    }

    /**
     * 创建Cookie 比如灰度 gray_level=fat
     * @param name
     * @param value
     * @param domain
     * @return
     */
    public Cookie getCookie(String name, String value, String domain) {
//        BasicCookieStore cookieStore = new BasicCookieStore();
        BasicClientCookie cookie = new BasicClientCookie(name, value);
        cookie.setDomain(domain);
        cookie.setPath("/");
//        cookieStore.addCookie(cookie);
        return cookie;
    }

    //
    // Cookie serialization/deserialization
    //

    protected String encodeCookie(SerializableCookie cookie) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(os);
            outputStream.writeObject(cookie);
        } catch (Exception e) {
            return null;
        }

        return byteArrayToHexString(os.toByteArray());
    }

    protected Cookie decodeCookie(String cookieStr) {
        byte[] bytes = hexStringToByteArray(cookieStr);
        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
        Cookie cookie = null;
        try {
            ObjectInputStream ois = new ObjectInputStream(is);
            cookie = ((SerializableCookie) ois.readObject()).getCookie();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return cookie;
    }

    // Using some super basic byte array <-> hex conversions so we don't have
    // to rely on any large Base64 libraries. Can be overridden if you like!
    protected String byteArrayToHexString(byte[] b) {
        StringBuffer sb = new StringBuffer(b.length * 2);
        for (byte element : b) {
            int v = element & 0xff;
            if (v < 16) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(v));
        }
        return sb.toString().toUpperCase();
    }

    protected byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }
}

Webview中的cookie设置简单说明

  • 参数中URL域名。例如链接https://www.baidu.com/ 需要变换为 www.baidu.com,不能带端口:8080)不带Http(s)://也不待任何后面拼接的连接地址/path,否则无效。

  • 设置cookie先将本地存储的cookie使用 for循环遍历后setCookie(String url, String value) 。如果是要手动添加额外的cookie则使用分号;拼接的 value 值,注意value 的值是使用key=value; domain="域名" ;的完整形式。文档提示 the cookie as a string, using the format of the 'Set-Cookie' HTTP response header,注意域名的正确性,否则会导致 Cookie不能完整设置或者无效。

  • CookieSyncManager 是个过时的类,Api21WebView 可以自动同步。 CookieSyncManager.getInstance().sync(); 被CookieManager.getInstance().flush()替代;其中Sync方法的本质调用的还是flush

  • 添加CookieloadUrl(url) 前一句调用进行 Cookie 同步操作。

  • cookieManager.setAcceptCookie(true);(自己测试结果不设置也生效)。

  • Cookie 同步方法要在WebViewsetting设置完之后调用,否则无效。(我测试的是oncreatesetContentView之后,可能是WebView为自定义的,所以相当于已经完成了setting的一系列设置)

  /**
     * webview中设置cookie
     * @param doMainHostNoProtocolURL 域名,不带有http和别的相关的拼接字段
     */
    public static void addLoginCookie(String doMainHostNoProtocolURL) {
        //登录成功后 重新设置webviewcookie信息 用来保持session一致...................start
        CookieSyncManager.createInstance(App.getInstance().getApplicationContext());
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        //获取本地存储的cookie
        List<Cookie> cookies = App.getPersistentCookiesList();
        for (int i = 0; i < cookies.size(); i++) {
            Cookie cookie = cookies.get(i);
            String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();
            cookieManager.setCookie(doMainHostNoProtocolURL, cookieString);
        }
        
        //根据需求手动拼接添加cookie进去
        if (!URLEnvironmentConfig.isForPublish()) {
            String cookieString = "gray_level=fat" + "; domain=" + doMainHostNoProtocolURL;
            cookieManager.setCookie(doMainHostNoProtocolURL, cookieString);

        }
        CookieSyncManager.getInstance().sync();
        //..................................................................end
    }

根据项目中的需求比如按照以下方式设置

BuildConfig.BuildEnvironmentDomain是根据build编译所需环境获取相应的生产、测试、预发布域名。


    public static void addLoginCookie() {
        //登录成功后 重新设置webviewcookie信息 用来保持session一致...................start
        CookieSyncManager.createInstance(App.getInstance().getApplicationContext());
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);//不设置也生效
        //获取本地存储的cookie
        List<Cookie> cookies = App.getPersistentCookiesList();
        for (int i = 0; i < cookies.size(); i++) {
            Cookie cookie = cookies.get(i);
            String cookieString = cookie.getName() + "=" + cookie.getValue() + "; domain=" + cookie.getDomain();
            cookieManager.setCookie(BuildConfig.BuildEnvironmentDomain, cookieString);
        }
        if (!URLEnvironmentConfig.isForPublish()) {
            String cookieString = "gray_level=fat" + "; domain=" + BuildConfig.BuildEnvironmentDomain;
            cookieManager.setCookie(BuildConfig.BuildEnvironmentDomain, cookieString);

        }
          String AccessToken = "AccessToken="+LoginManager.getAccessToken()+"; domain="+URLEnvironmentConfig.getAppDomainNoProtocol();
            cookieManager.setCookie(URLEnvironmentConfig.getAppDomainNoProtocol(), AccessToken);

            String memberId = "memberId="+LoginManager.getMemberId()+"; domain="+URLEnvironmentConfig.getAppDomainNoProtocol();
            cookieManager.setCookie(URLEnvironmentConfig.getAppDomainNoProtocol(), memberId);

            String cliver = "cliver="+URLManager.getClientVersion()+"; domain="+URLEnvironmentConfig.getAppDomainNoProtocol();
            cookieManager.setCookie(URLEnvironmentConfig.getAppDomainNoProtocol(), cliver);

            String devid = "devid="+DeviceUtil.getDeviceID()+"; domain="+URLEnvironmentConfig.getAppDomainNoProtocol();
            cookieManager.setCookie(URLEnvironmentConfig.getAppDomainNoProtocol(), devid);


        CookieSyncManager.getInstance().sync();
        //..................................................................end

    }

域名获取

/**
 * 获取URL的域名
 */
private String getDomain(String url){
  url = url.replace("http://", "").replace("https://", "");
  if (url.contains("/")) {
    //url=url.split("/")[0];
    url = url.substring(0, url.indexOf('/'));

  }
  return url;
}

请求域名不同问题

本人未测试先记录下:
两个不同接口A、B,保持相同的domainHostpathname。只有cookiedomainpath与请求的URL匹配才会发送这个cookie
以上保持相同的则前者和后者不一致会被后者替换、

package android.webkit;

  /**
     * Sets a cookie for the given URL. Any existing cookie with the same host,
     * path and name will be replaced with the new cookie. The cookie being set
     * will be ignored if it is expired.
     *
     * @param url the URL for which the cookie is to be set
     * @param value the cookie as a string, using the format of the 'Set-Cookie'
     *              HTTP response header
     */
    public abstract void setCookie(String url, String value);

WebView中设置UA

原则是先获取已有UA,再拼接新添加的部分,避免可能别的地方已经设置过了结果重新设置后覆盖掉。

String original = webView.getSettings().getUserAgentString();// 获取 WebView 的 UserAgent
original += " Version:" + versionName + ";";// 替换
webView.getSettings().setUserAgentString(original);// 设置新的 UserAgent

webview中添加请求头header设置、

private Map<String,String>  extraHeaders = new HashMap<>();
extraHeaders.put("x-app-token", App.getToken());
extraHeaders.put("x-app-deviceId",  App.getDeviceId()));
if (mWebView != null) {
    mWebView.loadUrl(targetUrl, extraHeaders);
}

参考地址

在HttpClient上配置Cookie管理
Android 控件WebView设置Cookie

相关文章

  • Android 接口请求添加cookie和webview中coo

    前言 服务端可能需要根据cookie值判定是否有登录、灰度环境、获取相关有效信息等用于区分当前用户。 HttpCl...

  • Android 开发中 Cookie 持久化研究

    参考:android WebView的cookie机制Android中Cookie获取、保存以及同步OkHttp3...

  • Android网络请求

    android网络请求 标签(空格分隔): android webview的用法MainActivity 需要添加...

  • Android中Webview的cookie设置

    Android中的webview相当于在App中新开了一个浏览器客户端,所以cookie不会和App的普通网络请求...

  • Android中WebView中的cookie设置

    Android中的webview相当于在App中新开了一个浏览器客户端,所以cookie不会和App的普通网络请求...

  • [Android]Cookie研究

    学习自:android WebView的cookie机制【WebView的cookie机制 】轻松搞定WebVie...

  • moco带cookie和headers请求

    moco可以接收带模拟cookie的请求,也可以模拟返回携带cookie的请求添加cookie和headers请求...

  • cookie

    参考:ios htttp网络请求cookie的读取与写入 NSHTTPCookieStorage(获取和删除coo...

  • Cookie/Session

    Cookie是什么:Cookie是请求头域和响应头域的字段。简单地说,就是伴随请求和响应的一组键值对的文本。Coo...

  • android okhttp3 cookie持久化管理

    今天项目遇到一个需求: 处于安全考虑, 要求登录后保存 cookie到本地, 后面所有接口请求时都需要带上 coo...

网友评论

      本文标题:Android 接口请求添加cookie和webview中coo

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