cookie会话保持
在我的实际场景中,我有一个用于AJAX的REST服务。 它为图形呈现数据系列。 我想用groovy出色的HttpBuilder进行测试。 但是,存在一个问题–这些请求仅适用于已登录的用户。 在这篇文章中,我提出了一个完整的解决方案来维护HttpBuilder请求之间的会话状态。
HttpBuilder中的会话
首先,快速提醒一下会话。 会话是HTTP请求状态的模拟,HTTP请求本质上是无状态的。 登录后,您将收到一个唯一的cookie(一个或多个),该cookie标识您的连续请求。 每次发送请求时,都会发送此cookie。 这样,服务器会识别您并将您与您的会话匹配,该会话将保留在服务器上。 一旦您注销或超时(例如,闲置20分钟后),Cookie就会被入侵。 下次访问页面时,您将获得一个新的唯一Cookie。
为了使会话在HttpBuilder中保持活动状态,我需要:
- 登录到我的Grails应用程序
- 收到JSESSIONID cookie作为回应
- 存储该cookie并将其与每个后续请求一起发送
我创建了包装HttpBuilder的RestConnector
类。 它的主要改进是将收到的Cookie保留在列表中。
package eu.spoonman.connectors.RestConnector
import groovyx.net.http.Method
import groovyx.net.http.ContentType
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.HttpResponseDecorator
class RestConnector {
private String baseUrl
private HTTPBuilder httpBuilder
private List<String> cookies
RestConnector(String url) {
this.baseUrl = url
this.httpBuilder = initializeHttpBuilder()
this.cookies = []
}
public def request(Method method, ContentType contentType, String url, Map<String, Serializable> params) {
debug("Send $method request to ${this.baseUrl}$url: $params")
httpBuilder.request(method, contentType) { request ->
uri.path = url
uri.query = params
headers['Cookie'] = cookies.join(';')
}
}
private HTTPBuilder initializeHttpBuilder() {
def httpBuilder = new HTTPBuilder(baseUrl)
httpBuilder.handler.success = { HttpResponseDecorator resp, reader ->
resp.getHeaders('Set-Cookie').each {
//[Set-Cookie: JSESSIONID=E68D4799D4D6282F0348FDB7E8B88AE9; Path=/frontoffice/; HttpOnly]
String cookie = it.value.split(';')[0]
debug("Adding cookie to collection: $cookie")
cookies.add(cookie)
}
debug("Response: ${reader}")
return reader
}
return httpBuilder
}
private debug(String message) {
System.out.println(message) //for Gradle
}
}
上一课中需要注意的几件事。 构造函数设置基本URL并创建可重用的HttpBuilder实例。 接下来,有一个成功请求的处理程序,用于检查我是否收到任何cookie。 它将收到的cookie添加到列表中。 最后,有一个调用HttpBuilder#request
的request
方法,但是它将cookie添加到HTTP标头中,以便服务器可以将我识别为登录用户。
发送每个请求的cookie是此处的核心部分。 它模拟浏览器的行为并维护会话。
如何使用它?
我将在下面的Spock测试中向您展示如何使用此实用程序类。 这很简单。
首先,我登录到我的应用程序,并确保我收到返回的cookie,这等效于登录。然后,我发送一个请求,并在HTTP标头中发送该cookie。 这是一个实现它的Spock测试:
package eu.spoonman.specs.rest
import eu.spoonman.connectors.RestConnector.RestConnector
import groovyx.net.http.ContentType
import groovyx.net.http.Method
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Stepwise
@Stepwise
class RestChartSpec extends Specification {
@Shared
RestConnector restConnector
def setupSpec() {
restConnector = new RestConnector('http://localhost:8080')
}
def "should login as test"() {
given:
Map params = [j_username: 'test', j_password: 'test']
when:
restConnector.request(Method.POST, ContentType.ANY, '/frontoffice/j_spring_security_check', params)
then:
!(restConnector.cookies.empty)
}
def "should allow access to chart data series"() {
given:
Map params = [days: 14]
when:
Map result = restConnector.request(Method.POST, ContentType.JSON, "frontoffice/chart/series", params)
then:
result != null
result.series.size() > 0
}
}
我使用应用程序的基本URL在setupSpec
创建一个新的RestConnector
实例。 请注意,它具有@Shared
批注,因此可以在测试之间共享。
@Stepwise
是此规范的关键注释。 这意味着Spock完全按照定义的顺序执行测试。 我需要确保首先执行登录。 我还需要断言我收到一个cookie,并且列表不为空。 我也可以将此步骤移到setupSpec
方法中,但我更喜欢将其作为规范中的第一个测试。 第二次测试始终在登录后执行,因此它将在请求标头中发送cookie。 这正是我想要实现的目标。
翻译自: https://www.javacodegeeks.com/2013/06/how-to-keep-session-in-httpbuilder-with-cookies.html
cookie会话保持