В этой статье
- retrofit / retrofit / src / main / java / retrofit2 / Response.java / Jump to Code definitions Class Response Method success Method success Method success Method success Method error Method error Method raw Method code Method message Method хедерs Method isSuccessful Method body Method errorBody Method toString Code navigation index up-to-date
- Get the Medium app
- Try и catch — обработка ошибок
- Footer
- Parsing Error Response
- Types of Errors
- Headers — передача заголовков
- OAuth2 Errors
- Authorization Request Errors
- Access Token Request Errors
- Refresh Token Request Errors
- POST запросы к серверу
Go to file
- TGo to file
- Go to lineL
- Go to definitionR
Copy path
- Copy permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. Cannot retrieve contributors at this time
164 lines (147 sloc)
5.27 KB
Raw
Blame
Edit this fileE
Open in GitHub Desktop
Open with Desktop
View raw
- Copy raw contents
Copy raw contents
Copy raw contents
Copy raw contents View blame
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
/* | |
* Copyright (C) 2015 Square, Inc. | |
* | |
* 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. | |
*/ | |
packageretrofit2; | |
importjava.util.Objects; | |
importjavax.annotation.Nullable; | |
importokhttp3.Headers; | |
importokhttp3.Protocol; | |
importokhttp3.Request; | |
importokhttp3.ResponseBody; | |
/** An HTTP response. */ | |
publicfinalclassResponse | |
/** Create a synthetic successful response with {@code body} as the deserialized body. */ | |
publicstatic | |
returnsuccess( | |
body, | |
newokhttp3.Response.Builder() // | |
.code(200) | |
.message(“OK”) | |
.protocol(Protocol.HTTP_1_1) | |
.request(newRequest.Builder().url(“http://localhost/”).build()) | |
.build()); | |
} | |
/** | |
* Create a synthetic successful response with an HTTP status code of {@code code} and {@code | |
* body} as the deserialized body. | |
*/ | |
publicstatic | |
if (code < 200 || code >= 300) { | |
thrownewIllegalArgumentException(“code < 200 or >= 300: ” + code); | |
} | |
returnsuccess( | |
body, | |
newokhttp3.Response.Builder() // | |
.code(code) | |
.message(“Response.success()”) | |
.protocol(Protocol.HTTP_1_1) | |
.request(newRequest.Builder().url(“http://localhost/”).build()) | |
.build()); | |
} | |
/** | |
* Create a synthetic successful response using {@code хедерs} with {@code body} as the | |
* deserialized body. | |
*/ | |
publicstatic | |
Objects.requireNonNull(хедерs, “хедерs == null”); | |
returnsuccess( | |
body, | |
newokhttp3.Response.Builder() // | |
.code(200) | |
.message(“OK”) | |
.protocol(Protocol.HTTP_1_1) | |
.хедерs(хедерs) | |
.request(newRequest.Builder().url(“http://localhost/”).build()) | |
.build()); | |
} | |
/** | |
* Create a successful response from {@code rawResponse} with {@code body} as the deserialized | |
* body. | |
*/ | |
publicstatic | |
Objects.requireNonNull(rawResponse, “rawResponse == null”); | |
if (!rawResponse.isSuccessful()) { | |
thrownewIllegalArgumentException(“rawResponse must be successful response”); | |
} | |
returnnewResponse<>(rawResponse, body, null); | |
} | |
/** | |
* Create a synthetic error response with an HTTP status code of {@code code} and {@code body} as | |
* the error body. | |
*/ | |
publicstatic | |
Objects.requireNonNull(body, “body == null”); | |
if (code < 400) thrownewIllegalArgumentException("code < 400: " + code); | |
returnerror( | |
body, | |
newokhttp3.Response.Builder() // | |
.body(newOkHttpCall.NoContentResponseBody(body.contentType(), body.contentLength())) | |
.code(code) | |
.message(“Response.error()”) | |
.protocol(Protocol.HTTP_1_1) | |
.request(newRequest.Builder().url(“http://localhost/”).build()) | |
.build()); | |
} | |
/** Create an error response from {@code rawResponse} with {@code body} as the error body. */ | |
publicstatic | |
Objects.requireNonNull(body, “body == null”); | |
Objects.requireNonNull(rawResponse, “rawResponse == null”); | |
if (rawResponse.isSuccessful()) { | |
thrownewIllegalArgumentException(“rawResponse should not be successful response”); | |
} | |
returnnewResponse<>(rawResponse, null, body); | |
} | |
privatefinalokhttp3.ResponserawResponse; | |
privatefinal@NullableTbody; | |
privatefinal@NullableResponseBodyerrorBody; | |
privateResponse( | |
okhttp3.ResponserawResponse, @NullableTbody, @NullableResponseBodyerrorBody) { | |
this.rawResponse = rawResponse; | |
this.body = body; | |
this.errorBody = errorBody; | |
} | |
/** The raw response from the HTTP client. */ | |
publicokhttp3.Responseraw() { | |
returnrawResponse; | |
} | |
/** HTTP status code. */ | |
publicintcode() { | |
returnrawResponse.code(); | |
} | |
/** HTTP status message or null if unknown. */ | |
publicStringmessage() { | |
returnrawResponse.message(); | |
} | |
/** HTTP хедерs. */ | |
publicHeadersхедерs() { | |
returnrawResponse.хедерs(); | |
} | |
/** Returns true if {@link #code()} is in the range [200..300). */ | |
publicbooleanisSuccessful() { | |
returnrawResponse.isSuccessful(); | |
} | |
/** The deserialized response body of a {@linkplain #isSuccessful() successful} response. */ | |
public@NullableTbody() { | |
returnbody; | |
} | |
/** The raw response body of an {@linkplain #isSuccessful() unsuccessful} response. */ | |
public@NullableResponseBodyerrorBody() { | |
returnerrorBody; | |
} | |
@Override | |
publicStringtoString() { | |
returnrawResponse.toString(); | |
} | |
} |
- Copy lines
- Copy permalink
- View git blame
- Reference in new issue
Go
Get the Medium app
Get started
Try и catch — обработка ошибок
При использовании любых сетевых запросов необходимо использовать обработку ошибок и исключительных ситуаций
try {…} catch(error){…}
<текстареа class="code">try {
var response = await http.get(‘https://json.flutter.su/echo’);
print(“Response status: ${response.statusCode}”);
print(“Response body: ${response.body}”);
} catch (error) {
print(error);
}
Данная конструкция позволит обработать ситуации когда нет доступа к сетевому ресурсу: выключена передача данных, отсутствует связь с сервером или указан неверный сетевой адрес.
В блоке try{…} выполняется код программы, если он не может быть выполнен — выполняется блок catch(error){…}.
текстареа>
© 2022 GitHub, Inc.
Parsing Error Response
The problem is how to parse the response if it’s not success. The idea is very simple. We need to create custom util for parsing the error. For example, we know that the server will return a JSON object with the following structure when an error occurs.
{
“success”: false,
“errors”: [
“Error message 1”,
“Error message 2”
]
}
We need to create a util for parsing the error. It returns an Object containing parsed error body. First, we define the class which represents the parsed error.
APIError.java
public class APIError {
private boolean success;
private ArrayList messages;
public static class Builder {
public Builder() {}
public Builder success(final boolean success) {
this.success = success;
return this;
}
public Builder messages(final ArrayList messages) {
this.messages = messages;
return this;
}
public Builder defaultError() {
this.messages.add(“Something error”);
return this;
}
public APIError build() { return new APIError(this); }
}
private APIError(final Builder builder) {
success = builder.successs;
messages = builder.messages;
}
}
And here’s the util for parsing the response body. If you have different response body format, you can adjust it to suit your case.
ErrorUtils.java
public class ErrorUtils {
public static APIError parseError(final Response> response) {
JSONObject bodyObj = null;
boolean success;
ArrayList messages = new ArrayList<>();
try {
String errorBody = response.errorBody().string();
if (errorBody != null) {
bodyObj = new JSONObject(errorBody);
success = bodyObj.getBoolean(“success”);
JSONArray errors = bodyObj.getJSONArray(“errors”);
for (int i = 0; i < errors.length(); i++) { messages.add(errors.get(i)); } } else { success = false; messages.add("Unable to parse error"); } } catch (Exception e) { e.printStackTrace();success = false; messages.add("Unable to parse error"); }return new APIError.Builder() .success(false) .messages(messages) .build(); } }
Finally, change the onResponse and onFailure methods. If response.isSuccessful() is false, we use the error parser. In addition, if the code go through onFailure which most likely we’re even unable to get the error response body, just return the default error.
Example.java
MyService myService = RetrofitClientInstance
.getRetrofitInstance()
.create(MyService.class);
Call<>
call.enqueue(new Callback<>
@Override
public void onResponse(final Call<>
if (response.isSuccessful()) {
List
Toast.makeText(getContext(), “Success”).show();
} else {
apiError = ErrorUtils.parseError(response);
Toast.makeText(getContext(), R.string.cashier_create_failed,
Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(final Call
apiError = new APIError.Builder().defaultError().build();
Toast.makeText(getContext(), “failed”).show();
}
});
That’s how to parse error body in Retrofit 2. If you also need to define custom GSON converter factory, read this tutorial.
Share on FacebookShare on TwitterShare on TumblrShare by E-MailShare on PinterestShare on LinkedInShare on RedditShare on Hacker News
Types of Errors
authorization | The authorization failed. |
expired_token | The OAuth token has expired. |
insufficient_permissions | The application has insufficient permissions to the resource. |
insufficient_scope | The application is missing a scope. |
invalid_client | The client_id provided is invalid. |
invalid_grant | The grant_type value provided is invalid. |
invalid_request | The request syntax provided is invalid. |
invalid_scope | The scope provided is invalid. |
invalid_token | The OAuth token provided is invalid. |
not_found | The resource with given id doesn’t exist. |
oauth | OAuth token is invalid, missing or expired. |
request | The API request failed. |
system | The system request failed. |
unsupported_grant_type | The grant_type provided is invalid. |
unsupported_response_type | The response_type provided is invalid. |
validation | Request parameter is invalid or missing. |
Headers — передача заголовков
Еще один параметр который может быть указан для всех методов — это заголовки хедерs (Map
<текстареа class="code">var response = await http.post(‘https://json.flutter.su/echo’,
хедерs: {‘Accept’:’application/json’,’Authorization’:’Basic YWxhZGRpbjpvcGVuc2VzYW1l’}
);текстареа>
OAuth2 Errors
Authorization Request Errors
According to the OAuth 2.0 RFC, if the redirect_uri is valid, the
user is redirected to the application’s redirect_uri, and any
errors are appended to the URI as a query string. However, this behavior could
be used in a phishing attack. Therefore, Fitbit’s OAuth 2.0 implementation
diverges from the spec in that the user will remain on
https://www.fitbit.com/oauth2/authorize
, and any errors will be displayed on the page.
All OAuth2 errors, excluding the Authorization Request Errors, will be
suffixed with:
“Visit https://dev.fitbit.com/reference/web-api/oauth2 for more information
on the Fitbit Web API authorization process.”
Like so:
{“errors”:[{“errorType”:”invalid_request”,”message”:”Missing parameters: refresh_token. Visit https://dev.fitbit.com/reference/web-api/oauth2 for more information on the Fitbit Web API authorization process.”}],”success”:false}
Access Token Request Errors
401 Unauthorized errors will occur when the “Authorization” хедер is invalid
or missing. In addition to an “errors” JSON object, the API will respond with
a WWW-Authenticate хедер and value of
Basic realm=”api.fitbit.com”. However, if the API cannot
determine the authentication scheme due to the Authorization хедер missing or
the word “Basic” being misspelled, the WWW-Authenticate хедер
will return the value Bearer realm=”api.fitbit.com”.
Refresh Token Request Errors
For 401 Unauthorized errors that occur during a refresh token request, the API
will respond with a WWW-Authenticate хедер and a value of
Bearer realm=”api.fitbit.com”, rather than a value of Basic
realm=”[redirect_uri]”.
On rare occasions, the application may encounter a 409 Conflict error for
concurrent refresh token requests. The avoid this error, applications should
avoid making multiple, concurrent refresh token requests. Verify the refresh
token process was not started for the same token more than once, and, where
applicable, coordinate refresh token requests across processes.
POST запросы к серверу
В post запросах можно передавать данные в теле запроса с помощью параметра body и кодировку encoding если она отличается от utf-8 (по умолчанию), синхронное выполнение метода с помощью await:
<текстареа class="code">var response = await http.post(‘https://json.flutter.su/echo’, body: {‘name’:’test’,’num’:’10’});
print(“Response status: ${response.statusCode}”);
print(“Response body: ${response.body}”);В параметре body вы можете передать: [String], [List
- https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit2/Response.java
- https://medium.com/@Dalvin/how-to-parse-http-error-body-using-retrofit-bb348f67fc54
- https://flutter.su/tutorial/7-HTTP-network-requests
- https://www.woolha.com/tutorials/android-retrofit-2-custom-error-response-handling
- https://dev.fitbit.com/build/reference/web-api/troubleshooting-guide/error-handling/