简介:
通过源码,我们来一步步分析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) { 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() { 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)) { return; } Duration timeout = std::min( http::errorRetryTimeout(failedRequestReason, failedRequests, retryAfter), http::expirationTimeout(expires, expiredRequests)); if (timeout == Duration::max()) { return; } 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); 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 { 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); 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(); }
|
到这里网络请求的过程便梳理完了