zcpHappy 2014-11-18
先说调研的结果
url的参数是hash形式,比如state={user_id: 2, sign='hello'},如果写到url里应该写成:
http://root/path?state[user_id]=2&state[sign]=%2Fhello(注:引号需要编码)
下面找到这个答案的过程:
1、查url参数:URL 参数是追加到 URL 上的一个名称/值对,参数以问号"?"开始并采用 name=value 的格式。多个参数时参数之间用“&”符号隔开。如:http://server/path/document?name1=value1&name2=value2;
1.1value常用的类型是string,也可以是数组,对象
1.2如果是数组,就写成name[1,2],数组的元素之间不要用空格,如果真的需要就对参数编码。如:http://server/path/document?name=[1,2]或者http://server/path/document?name=%5b2%2c+3%5d
1.3如果是对象,不要写成name={key_1: value_1, key_2: value_2}的形式,直接写成key-value形式,即使进行编码也会报baduri的错误,正确的写法应该是:name[key_1]=value_1&name[key_2]=value_2.如:http://server/path/document?name[key_1]=value_1&name[key_2]=value_2
2、因为用request测试,发现get方法传的第二个参数即是url的参数,但是这个参数是原味的hash,如下:
写了一个request测试用例A:
it "should login" do
state = {user_id: user.id, redirect_url: '/mobile'}
get "/mobile/login", {state: state, code: code}
expect(response).to redirect_to('/mobile')
end
state是所传的参数,是个hash形式,如果url写成:get "/mobile/login?{state: {user_id: user.id, redirect_url: '/mobile}, code: '123’}”就报错了:bidder。
刚开始对baduri的错误信息不知道如何打log看更多信息,就直接查baduri的错误,没有找到参数是hash的url,所以也就不知道参数是hash的url到底哪不对;然后尝试将hash参数进行encode编码,依然报baduri的 错误;
之前对引入的第三方库的代码,也就是源码,很少去看,更不会想到通过源码去调试。经前辈循序渐进的指点,才去看源码,尝试在源码的get方法里打log,发现打不出log,但是确实跟踪到get方法的源码了,就想当然地认为无法在控制台打印出第三方库的信息;然后只好老实地读代码,但是发现源码的方法一个套一个,这也无所谓,我只要知道url组成的方法就行,所以找到build_url的方法,里面同样套了很多方法,而且看不懂的代码也不少,实在读不下去了,最后想硬着头皮去查,打算弄懂所有的代码,可是这样做很不现实,等弄明白的时候都不知道何年何月了。在尝试在源码里打log的做法失败后,只好继续去读源码,可能是资料看得多了,最关键词有一定敏感度了,再看源码,居然注意到了request和response变量,reponse实在request请求之后得到的响应,那么排除response,也就是request了,最后在build_request_uri方法里发现了四行行很有用的代码:
line1: url, query_string = @routes.url_for(options).split("?", 2)
line2: @request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
line3: @request.env["PATH_INFO"] = url
line4: @request.env["QUERY_STRING"] = query_string || “"
猜测line1是将url通过“?”分成两部分分别赋值给url喝query_string, 那么query_string就是url所带的参数,跟着看到line4中将query_string赋值给@request.env["QUERY_STRING”],所以我猜测要的url参数就是@request.env["QUERY_STRING”]了,然后就试着在测试用例A的get请求之后打印出@request.env["QUERY_STRING”]:
it "should login" do
state = {user_id: user.id, redirect_url: '/mobile'}
get "/mobile/login", {state: state, code: code}
p @request.env["QUERY_STRING”]
expect(response).to redirect_to('/mobile')
end
打印的结果是:“state[user_id]=2&state[redirect_url]=%2Fmobile&code=123”,现在结果已经出来了,hash参数是可以传的,但是需要将每个元素单独拿出来做参数放在url里。
在调试的过程中,前辈提醒我去读源码,但是一看源码那么多,就读不下去了,放弃读源码后,又是一阵瞎猜乱试,甚至到最后都忘了自己是为了找出hash的参数是如何组装的,而变成否定url中的参数不能是hash形式的。调试不能单纯地靠猜,靠瞎调试;读源码要抓住关键信息,不必弄明白所有的源码。