我是Volley和OkHttp的新手,我正在尝试使用 OkHttp作为Volley 的传输层登录网站。 登录需要通过SSL完成,并实现了几个重定向。
OkHttp被迫不自动跟踪重定向,因为我需要手动为此站点执行此操作(我认为),但我在发布请求时失败(我不确定)。
帖子请求需要一些这样的参数:
source=AEM&target=IAM&URL=selfcare&login-form-type=pwd&username=user&userId=user&password=pass&rememberUsername=yes&button=
所以如果我没有弄错的话应该是StringRequest,而且我需要覆盖所有请求的标题,如下所示:
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Connection", "keep-alive");
params.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36");
params.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
return params;
}
如果有人可以忽略我的代码,看看我哪里出错了,我将不胜感激。再一次,我是排球和okhttp的新手,所以downvoters应该温柔。
修改
对于遇到同样问题的人。
我终于在PersistentCookieStore(https://gist.github.com/franmontiel/ed12a2295566b7076161)的帮助下成功登录了。
此外,我需要制作一个同步的RequestQueue ,以便能够手动关注所有重定向。 (这可以通过使用 FutureRequest 来改进,但它可以工作,随时根据您的需要更改以下工作代码。
Singleton类:
public class TestController extends Application {
public static final String TAG = "VolleyPatterns";
private RequestQueue mRequestQueue;
private static TestController sInstance;
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
}
public static synchronized TestController getInstance() {
return sInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new OkHttpStack());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
VolleyLog.e("Adding request to queue: %s", req.getUrl());
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
OkHttpStack类(SSL允许所有证书用于测试目的):
public class OkHttpStack extends HurlStack {
private final OkUrlFactory okUrlFactory;
public OkHttpStack() {
this(new OkUrlFactory(getOkHttpClient()));
}
public OkHttpStack(OkUrlFactory okUrlFactory) {
if (okUrlFactory == null) {
throw new NullPointerException("Client must not be null.");
}
this.okUrlFactory = okUrlFactory;
}
private static OkHttpClient getOkHttpClient() {
if (BuildConfig.DEBUG) {
return getUnsafeOkHttpClient();
} else {
return new OkHttpClient();
}
}
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setFollowRedirects(false);
okHttpClient.setSslSocketFactory(sslSocketFactory);
okHttpClient.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
protected HttpURLConnection createConnection(URL url) throws IOException {
return okUrlFactory.open(url);
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
private String LOGINURL = "https://www.test.com/testhandler/iam/authenticateuser/";
private static String redirectURL;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CookieManager cmrCookieMan = new CookieManager(new PersistentCookieStore(this), CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cmrCookieMan);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final StringRequest postRequest = new StringRequest(Request.Method.POST, LOGINURL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("Response", response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
redirectURL = null;
final int status = error.networkResponse.statusCode;
if (HttpURLConnection.HTTP_MOVED_PERM == status || status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_SEE_OTHER) {
redirectURL = error.networkResponse.headers.get("Location");
Log.e("Redirected to ", redirectURL);
Log.d("ERROR", "error => " + error.toString());
LoadFirst();
Log.w("1st ", "Link");
}
}
}
) {
@Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=utf-8";
}
// this is the relevant method
@Override
public byte[] getBody() throws AuthFailureError {
String httpPostBody ="username=yser&password=pass";
try {
httpPostBody = httpPostBody + URLEncoder.encode("", "UTF-8");
} catch (UnsupportedEncodingException exception) {
Log.e("ERROR", "exception", exception);
return null;
}
return httpPostBody.getBytes();
}
};
TestController.getInstance().addToRequestQueue(postRequest);
}
private void LoadFirst() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, redirectURL,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.e("Response:", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
redirectURL = null;
final int status = error.networkResponse.statusCode;
if (HttpURLConnection.HTTP_MOVED_PERM == status || status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_SEE_OTHER) {
redirectURL = error.networkResponse.headers.get("Location");
Log.e("2nd Redirect to ", redirectURL);
LoadSecond();
Log.w("2nd ", "Link");
}
}
});
TestController.getInstance().addToRequestQueue(stringRequest);
}
private void LoadSecond() {
StringRequest stringRequest = new StringRequest(Request.Method.GET, redirectURL,
new Response.Listener<String>() {
@Override
public void onResponse(String s) {
//Search the secretUserID in the response, which is only provided after successfull login
for (String line : s.split("\n")) {
if (line.contains("secretUserID")) {
String[] out = line.split("'");
String CustID = out[1].toString();
Log.w("secretUserID", CustID);
}
}
Log.w("3rd FINAL ", "Successfully logged in!");
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("Fatal error: ", error.toString());
if (error instanceof TimeoutError) {
// note : may cause recursive invoke if always timeout.
Log.e("Timed out ", "retrying..");
LoadSecond();
}
}
});
stringRequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 2,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
TestController.getInstance().addToRequestQueue(stringRequest);
}
}
logcat的:
03-23 16:19:46.791 5847-5878/test.com.example.buddy.myapplication D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
03-23 16:19:46.846 5847-5878/test.com.example.buddy.myapplication I/OpenGLRenderer: Initialized EGL, version 1.4
03-23 16:19:47.534 5847-5877/test.com.example.buddy.myapplication E/Volley: [1644] BasicNetwork.performRequest: Request at https://www.test.com/testhandler/iam/authenticateuser/ has been redirected to https://www.test.com/login.login/?url=%2Ftesthandler%2Fiam%2Fauthenticateuser%2F
03-23 16:19:47.538 5847-5847/test.com.example.buddy.myapplication E/Redirected to: https://www.test.com/login.login/?url=%2Fztesthandler%2Fiam%2Fauthenticateuser%2F
03-23 16:19:47.538 5847-5847/test.com.example.buddy.myapplication D/ERROR: error => com.android.volley.RedirectError
03-23 16:19:47.540 5847-5847/test.com.example.buddy.myapplication W/1st: Link
03-23 16:19:47.611 5847-5874/test.com.example.buddy.myapplication E/Volley: [1641] BasicNetwork.performRequest: Request at https://www.test.com/login.login/?url=%2Ftesthandler%2Fiam%2Fauthenticateuser%2F has been redirected to https://www.test.com/test/?selfcare
03-23 16:19:47.612 5847-5847/test.com.example.buddy.myapplication E/2nd Redirect to: https://www.test.com/test/?selfcare
03-23 16:19:47.612 5847-5847/test.com.example.buddy.myapplication W/2nd: Link
03-23 16:19:51.533 5847-5875/test.com.example.buddy.myapplication D/Volley: [1642] BasicNetwork.logSlowRequests: HTTP response for request=<[ ] https://www.test.com/test/?selfcare 0xe5b1fae3 NORMAL 3> [lifetime=3920], [size=34928], [rc=200], [retryCount=0]
03-23 16:19:51.544 5847-5847/test.com.example.buddy.myapplication W/encryptedCustID: someUserID
03-23 16:19:51.545 5847-5847/test.com.example.buddy.myapplication W/3rd FINAL: Successfully logged in!