禁用Cookie后,Session怎么样使用?

上一篇文章中描述了使用Session来保持客户端与服务端交互状态的一致,解决无状态的HTTP协议在动态应用中的使用(后台回复关键字005查看之)。

在上篇中更多的是在分析通过Session Cookie这一方式,在每次请求时都将

sessionId以Cookie的形式发到服务端,来保持一致。这也是许多人印象中的

Session在浏览器关闭之后就失效这一说法的来源。

其实本质上是浏览器在关闭之后,应用对应的SessionCookie被清除了,再次打开浏览器请求应用时,之前的SessionId对应的Cookie不存在,所以就会重新创建一个Session。而服务端原来的Session其实还是存在的,只是没人与之对应,就默默的等着超时时间一到,被清除了。

而对于Cookie,我们都知道其是浏览器保存客户端本地的,安全问题暂且不说,但Cookie是可以在浏览器中配置后关闭的。关闭之后,服务器就不能再向浏览器写Cookie的,此时我们基于SessionCookie的实现方式就遇到了问题。

虽然每一次仍然通过response将Set-Cookie添加到header里,但发到浏览器的时候,不能再写Cookie,后续的请求依然是重新发一个sessionId为null的请求,导致每次仍是重新创建session对象,并没有解决交互状态的问题。

为了解决这个问题,服务器提供了另外一种方式:

URL重写,即英文的URLrewrite。

这一方式,其本质上是在每次请求的url后面append 上一个类似于jsessionid=xxxx这样的参数,在服务端解析时,获取到jsessionid对应的值,并根据其获取到对应的Session对象,从而保证了交互状态一致。

一句话就说明白了。

但这一句话背后,有一些事情还是需要注意的,

例如,我们可以自己在url后面写上jsessionid=当前session的id值。这种类似于硬编码,因为服务端获取这个session的id是通过jsessionid这个参数名来获取的,而这个参数我们在前一篇文章中了解到,是可以配置的,当改了之后,后面的sessionId就获取不到了。

其次,为了保证各类url规则的一致,服务端提供了response API来处理,只需要直接使用,就可以完成jsessionid的参数追加。

/**
 * Encode the session identifier associated with this response
 * into the specified URL, if necessary.
 *
 * @param url URL to be encoded
 */
@Override
public String encodeURL(String url) {

    String absolute;
    try {
        absolute = toAbsolute(url);
    } catch (IllegalArgumentException iae) {
        // Relative URL
        return url;
    }

    if (isEncodeable(absolute)) {//关键在这里
        // W3c spec clearly said
        if (url.equalsIgnoreCase("")) {
            url = absolute;
        } else if (url.equals(absolute) && !hasPath(url)) {
            url += '/';
        }
        return (toEncoded(url, request.getSessionInternal().getIdInternal()));
    } else {
        return (url);
    }

}

我们看代码中的实现逻辑:

/**
 * Return <code>true</code> if the specified URL should be encoded with
 * a session identifier.  This will be true if all of the following
 * conditions are met:
 * <ul>
 * <li>The request we are responding to asked for a valid session
 * <li>The requested session ID was not received via a cookie
 * <li>The specified URL points back to somewhere within the web
 *     application that is responding to this request
 * </ul>
 *
 * @param location Absolute URL to be validated
 */
protected boolean isEncodeable(final String location) {

    if (location == null) {
        return (false);
    }

    // Is this an intra-document reference?
    if (location.startsWith("#")) {
        return (false);
    }

    // Are we in a valid session that is not using cookies?
    final Request hreq = request;
    final Session session = hreq.getSessionInternal(false);
    if (session == null) {
        return (false);
    }
    if (hreq.isRequestedSessionIdFromCookie()) {
        return (false);
    }

    // Is URL encoding permitted
    if (!hreq.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.URL)) {
        return false;
    }

    return doIsEncodeable(hreq, session, location);
    
}

代码中会根据是否使用SessionCookie来决定是否要继续,

之后会继承判断可使用的Session tracking Mode里都有哪些,是否包含URL。


在doIsEncodeable方法中,最终实现是这一行代码

        String tok = ";" +
                SessionConfig.getSessionUriParamName(request.getContext()) +
                "=" + session.getIdInternal();

也就是我们上面提到的硬编码jsessionid到url后面不太好的原因,这里就是在读取它的配置。

public static String getSessionUriParamName(Context context) {

String result = getConfiguredSessionCookieName(context);

if (result == null) {

result = DEFAULT_SESSION_PARAMETER_NAME;

}

return result;

}

另外,我们上面提到的Session tracking Mode,是在Tomcat启动的时候判断的,而服务端并不可能得知以后要连接的浏览器中,哪些是不允许Cookie的,所以对于Sesion tracking mode,URL无论如何都是可以使用的,而Session cookie是否要使用,是通过在Context组件中配置的其cookies属性为false时禁止的

private void populateSessionTrackingModes() {

// URL re-writing is always enabled by default

defaultSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL);

supportedSessionTrackingModes = EnumSet.of(SessionTrackingMode.URL);

if (context.getCookies()) { //此处读取Context组件的cookies配置,如果为false,则不使用SessionCookie

defaultSessionTrackingModes.add(SessionTrackingMode.COOKIE);

supportedSessionTrackingModes.add(SessionTrackingMode.COOKIE); }

总结下,即为了防止客户端禁用Cookie导致的Session状态不一致的情况,我们可以采用UrlRewrite的方式来保证。

这一过程,我们可以使用response的encodeURL方法来使sessionid添加到url后面,不过是需要先在Context组件中声明不使用cookies。

长按即可关注!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值