Mapbox源码分析之发送请求

简介:

通过源码,我们来一步步分析Mapbox地图引擎如何发送网络请求的,这里是基于5.3.0的版本.

Mapbox源码分析之url解析这篇里我们了解了mapbox如何将自定义的常量字符串解析出它需要的url地址,那么当url解析出来之后应该便是发送请求了,这里我们看到online_file_source.cpp文件的request()方法看起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource, Callback callback) {
Resource res = resource;
switch (resource.kind) {
case Resource::Kind::Unknown:
case Resource::Kind::Image:
break;
case Resource::Kind::Style:
res.url = mbgl::util::mapbox::normalizeStyleURL(apiBaseURL, resource.url, accessToken);
break;
case Resource::Kind::Source:
res.url = util::mapbox::normalizeSourceURL(apiBaseURL, resource.url, accessToken);
break;
case Resource::Kind::Glyphs:
res.url = util::mapbox::normalizeGlyphsURL(apiBaseURL, resource.url, accessToken);
break;
case Resource::Kind::SpriteImage:
case Resource::Kind::SpriteJSON:
res.url = util::mapbox::normalizeSpriteURL(apiBaseURL, resource.url, accessToken);
break;
case Resource::Kind::Tile:
res.url = util::mapbox::normalizeTileURL(apiBaseURL, resource.url, accessToken);
break;
}
return std::make_unique<OnlineFileRequest>(std::move(res), std::move(callback), *impl);
}

这里我们看到当url解析完之后,返回了一个OnlineFileRequest对象,我们看下它的构造方法

1
2
3
4
5
6
OnlineFileRequest::OnlineFileRequest(Resource resource_, Callback callback_, OnlineFileSource::Impl& impl_)
: impl(impl_),
resource(std::move(resource_)),
callback(std::move(callback_)) {
impl.add(this);
}

这里我们看到它赋值了Impl,resource,callback对象,并且调用了impl.add()方法,我们继续看

1
2
3
4
5
6
7
8
9
10
11
12
13
void add(OnlineFileRequest* request) {
allRequests.insert(request);
if (resourceTransform) {
// Request the ResourceTransform actor a new url and replace the resource url with the
// transformed one before proceeding to schedule the request.
resourceTransform->invoke(&ResourceTransform::transform, request->resource.kind,
std::move(request->resource.url), [ref = request->actor()](const std::string&& url) mutable {
ref.invoke(&OnlineFileRequest::setTransformedURL, std::move(url));
});
} else {
request->schedule();
}
}

在这里我们看到它将请求添加到请求集合中,并加调用request->schedule();继续往下看

1
2
3
4
5
6
7
8
void OnlineFileRequest::schedule() {
// Force an immediate first request if we don't have an expiration time.
if (resource.priorExpires) {
schedule(resource.priorExpires);
} else {
schedule(util::now());
}
}

这里我们看到它判断了请求执行是否有延迟,继续往下看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void OnlineFileRequest::schedule(optional<Timestamp> expires) {
if (impl.isPending(this) || impl.isActive(this)) {
// There's already a request in progress; don't start another one.
return;
}
// If we're not being asked for a forced refresh, calculate a timeout that depends on how many
// consecutive errors we've encountered, and on the expiration time, if present.
Duration timeout = std::min(
http::errorRetryTimeout(failedRequestReason, failedRequests, retryAfter),
http::expirationTimeout(expires, expiredRequests));
if (timeout == Duration::max()) {
return;
}
// Emulate a Connection error when the Offline mode is forced with
// a really long timeout. The request will get re-triggered when
// the NetworkStatus is set back to Online.
if (NetworkStatus::Get() == NetworkStatus::Status::Offline) {
failedRequestReason = Response::Error::Reason::Connection;
failedRequests = 1;
timeout = Duration::max();
}
timer.start(timeout, Duration::zero(), [&] {
impl.activateOrQueueRequest(this);
});
}

到这里我们看到,它判断了请求是否是激活的以及时间是否超限,这里我们看impl.activateOrQueueRequest(this);这行代码

1
2
3
4
5
6
7
8
9
10
11
void activateOrQueueRequest(OnlineFileRequest* request) {
assert(allRequests.find(request) != allRequests.end());
assert(activeRequests.find(request) == activeRequests.end());
assert(!request->request);
if (activeRequests.size() >= HTTPFileSource::maximumConcurrentRequests()) {
queueRequest(request);
} else {
activateRequest(request);
}
}

这里我们看到它根据请求的数量将请求进行队列或者激活处理,这里我们看激活请求方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void activateRequest(OnlineFileRequest* request) {
auto callback = [=](Response response) {
activeRequests.erase(request);
request->request.reset();
request->completed(response);
activatePendingRequest();
};
activeRequests.insert(request);
if (online) {
request->request = httpFileSource.request(request->resource, callback);
} else {
Response response;
response.error = std::make_unique<Response::Error>(Response::Error::Reason::Connection,
"Online connectivity is disabled.");
callback(response);
}
assert(pendingRequestsMap.size() == pendingRequestsList.size());
}

到这里我们看到了它调用了httpFileSource.request()方法,我们继续往下看

1
2
3
std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource, Callback callback) {
return std::make_unique<HTTPRequest>(*impl->env, resource, callback);
}

这里我们看到它实例化了HTTPRequest对象,那么我们便看看HTTPRequest对象的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HTTPRequest::HTTPRequest(jni::JNIEnv& env, const Resource& resource_, FileSource::Callback callback_)
: resource(resource_),
callback(callback_) {
std::string etagStr;
std::string modifiedStr;
if (resource.priorEtag) {
etagStr = *resource.priorEtag;
} else if (resource.priorModified) {
modifiedStr = util::rfc1123(*resource.priorModified);
}
jni::UniqueLocalFrame frame = jni::PushLocalFrame(env, 10);
static auto constructor =
javaClass.GetConstructor<jni::jlong, jni::String, jni::String, jni::String>(env);
javaRequest = javaClass.New(env, constructor,
reinterpret_cast<jlong>(this),
jni::Make<jni::String>(env, resource.url),
jni::Make<jni::String>(env, etagStr),
jni::Make<jni::String>(env, modifiedStr)).NewGlobalRef(env);
}

到这里我们看到了它并未做什么处理,只是初始化了一些对象,那么请求是如何发出的呢?那么我们看看它new的这个javaClass对象是什么吧

1
static jni::Class<HTTPRequest> javaClass;

原来new的这个对象是java层的HTTPRequest对象,那么我们回到java层看一下这个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) {
mNativePtr = nativePtr;
try {
HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
// Don't try a request to remote server if we aren't connected
if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
throw new NoRouteToHostException("No Internet connection available.");
}
if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
|| host.endsWith(".mapbox.cn")) {
if (httpUrl.querySize() == 0) {
resourceUrl = resourceUrl + "?";
} else {
resourceUrl = resourceUrl + "&";
}
resourceUrl = resourceUrl + "events=true";
}
Request.Builder builder = new Request.Builder()
.url(resourceUrl)
.tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
.addHeader("User-Agent", getUserAgent());
if (etag.length() > 0) {
builder = builder.addHeader("If-None-Match", etag);
} else if (modified.length() > 0) {
builder = builder.addHeader("If-Modified-Since", modified);
}
mRequest = builder.build();
mCall = mClient.newCall(mRequest);
mCall.enqueue(this);
} catch (Exception exception) {
onFailure(exception);
}
}

到这里就看明白了,这里对url进行了一些判断处理后,通过OkHttpClient发出请求的,既然我们看明白了请求发送过程,那顺便看看拿到请求数据之后的处理吧,这里我们看到HTTPRequest覆盖的onResponse()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
Timber.v("[HTTP] Request was successful (code = %s).", response.code());
} else {
// We don't want to call this unsuccessful because a 304 isn't really an error
String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information";
Timber.d("[HTTP] Request with response code = %s: %s", response.code(), message);
}
byte[] body;
try {
body = response.body().bytes();
} catch (IOException ioException) {
onFailure(ioException);
// throw ioException;
return;
} finally {
response.body().close();
}
mLock.lock();
if (mNativePtr != 0) {
nativeOnResponse(response.code(),
response.header("ETag"),
response.header("Last-Modified"),
response.header("Cache-Control"),
response.header("Expires"),
response.header("Retry-After"),
response.header("x-rate-limit-reset"),
body);
}
mLock.unlock();
}

这里我们看到拿到响应数据之后便通过nativeOnResponse()方法传入底层了,那么我们看看底层对应的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
void HTTPRequest::onResponse(jni::JNIEnv& env, int code,
jni::String etag, jni::String modified,
jni::String cacheControl, jni::String expires,
jni::String jRetryAfter, jni::String jXRateLimitReset,
jni::Array<jni::jbyte> body) {
using Error = Response::Error;
if (etag) {
response.etag = jni::Make<std::string>(env, etag);
}
if (modified) {
response.modified = util::parseTimestamp(jni::Make<std::string>(env, modified).c_str());
}
if (cacheControl) {
const auto cc = http::CacheControl::parse(jni::Make<std::string>(env, cacheControl).c_str());
response.expires = cc.toTimePoint();
response.mustRevalidate = cc.mustRevalidate;
}
if (expires) {
response.expires = util::parseTimestamp(jni::Make<std::string>(env, expires).c_str());
}
if (code == 200) {
if (body) {
auto data = std::make_shared<std::string>(body.Length(env), char());
jni::GetArrayRegion(env, *body, 0, data->size(), reinterpret_cast<jbyte*>(&(*data)[0]));
response.data = data;
} else {
response.data = std::make_shared<std::string>();
}
} else if (code == 204 || (code == 404 && resource.kind == Resource::Kind::Tile)) {
response.noContent = true;
} else if (code == 304) {
response.notModified = true;
} else if (code == 404) {
response.error = std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404");
} else if (code == 429) {
optional<std::string> retryAfter;
optional<std::string> xRateLimitReset;
if (jRetryAfter) {
retryAfter = jni::Make<std::string>(env, jRetryAfter);
}
if (jXRateLimitReset) {
xRateLimitReset = jni::Make<std::string>(env, jXRateLimitReset);
}
response.error = std::make_unique<Error>(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset));
} else if (code >= 500 && code < 600) {
response.error = std::make_unique<Error>(Error::Reason::Server, std::string{ "HTTP status code " } + std::to_string(code));
} else {
response.error = std::make_unique<Error>(Error::Reason::Other, std::string{ "HTTP status code " } + std::to_string(code));
}
async.send();
}

到这里网络请求的过程便梳理完了