前言

RxHttp是基于RxJava2+Retrofit 2.9.0+OkHttp 4.9.0实现的轻量级,完美兼容MVVM架构的网络请求封装类库,小巧精致,简单易用,轻轻松松搞定网络请求。

GitHub

https://github.com/kongpf8848/RxHttp

亮点

  • 代码量极少,类库大小不足100kb,但足以胜任大部分APP的网络请求任务,浓缩的都是精华啊_^_

  • 完美兼容MVVM,MVC架构,兼容Kotlin和Java,Kotlin+MVVM+RxHttp组合使用更酸爽,MVVM官方推荐,抱紧Google大腿就对了

  • 完美解决泛型类型擦除的棘手问题,还原泛型的真实类型

  • 天生支持网络请求和Activity,Fragment生命周期绑定,界面销毁时自动取消网络请求回调

  • 天生支持多BaseUrl,支持动态传入Url

  • 支持自定义OkHttpClient.Builder,可高度自定义网络请求参数

  • 支持Glide等和网络请求公用一个OkHttpClient,充分利用OkHttpClient的线程池和连接池,大部分情况下一个App一个OkHttpClient就够了

  • 支持GET,POST,PUT,DELETE等请求方式,支持文件上传及进度监听,支持同时上传多个文件,支持Uri上传

  • 支持文件下载及进度监听,支持大文件下载,支持断点下载

使用要求

项目基于AndroidX,Java8+,minSdkVersion>=21

使用

implementation 'com.github.kongpf8848:RxHttp:1.0.11'

配置(可选)

  RxHttpConfig.getInstance()
/**
* 失败重试次数
*/
.maxRetries(3)
/**
* 每次失败重试间隔时间
*/
.retryDelayMillis(200)
/**
* 自定义OkHttpClient.Builder(),RxHttp支持自定义OkHttpClient.Builder(),
* 如不定义,则使用RxHttp默认的OkHttpClient.Builder()
*/
.builder(OkHttpClient.Builder().apply {
connectTimeout(60, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(60, TimeUnit.SECONDS)
/**
* DEBUG模式下,添加日志拦截器,建议使用RxHttp中的FixHttpLoggingInterceptor,使用OkHttp的HttpLoggingInterceptor在上传下载的时候会有IOException问题
*/
if (BuildConfig.DEBUG) {
addInterceptor(FixHttpLoggingInterceptor().apply {
level = FixHttpLoggingInterceptor.Level.BODY
})
}
})

基础使用

  • GET/POST/PUT/DELETE/上传请求
   RxHttp.getInstance()
/**
* get:请求类型,可为get,post,put,delete,upload,分别对应GET/POST/PUT/DELETE/上传请求
* context:上下文,可为Context,Activity或Fragment类型,当context为Activity或Fragment时网络请求和生命周期绑定
*/
.get(context)
/**
* 请求url,如https://www.baidu.com
*/
.url("xxx")
/**
*请求参数键值对,类型为Map<String, Any?>?,如hashMapOf("name" to "jack")
*/
.params(map)
/**
*每个网络请求对应的tag值,可为null,用于后续手动根据tag取消指定网络请求
*/
.tag("xxx")
/**
* HttpCallback:网络回调,参数xxx为返回数据对应的数据模型,
* 类似RxJava中的Observer,onComplete只有在onNext回调之后执行,如发生错误则只会回调onError而不会执行onComplete
*/
.enqueue(object : HttpCallback<xxx>() {
/**
* http请求开始时回调
*/
override fun onStart() { } /**
* http请求成功时回调
*/
override fun onNext(response: xxx?) { } /**
* http请求失败时回调
*/
override fun onError(e: Throwable?) { } /**
* http请求成功完成时回调
*/
override fun onComplete() { } /**
* 上传进度回调,请求类型为upload时才会回调
*/
override fun onProgress(readBytes: Long, totalBytes: Long) { }
})
  • 下载请求
   RxHttp.getInstance()
/**
* download:请求类型,下载请求
* context:上下文,如不需要和生命周期绑定,应该传递applicationContext
*/
.download(context)
/**
* 保存路径
*/
.dir(dir)
/**
*保存文件名称
*/
.filename(filename)
/**
* 是否为断点下载,默认为false
*/
.breakpoint(true)
/**
* 下载地址,如http://study.163.com/pub/ucmooc/ucmooc-android-official.apk
*/
.url(url)
/**
* 请求Tag
*/
.tag(null)
/**
* 下载回调
*/
.enqueue(object: DownloadCallback() {
/**
* 下载开始时回调
*/
override fun onStart() { } /**
* 下载完成时回调
*/
override fun onNext(response: DownloadInfo?) { } /**
* 下载失败时回调
*/
override fun onError(e: Throwable?) { } /**
* 下载完成之后回调
*/
override fun onComplete() { } /**
* 下载进度回调
*/
override fun onProgress(readBytes: Long, totalBytes: Long) { } })
  • 取消请求
    /**
* tag:Any?,请求Tag,对应网络请求里的Tag值
* 如不为null,则取消指定网络请求,
* 如为null,则取消所有网络请求
*/
RxHttp.getInstance().cancelRequest(tag)

项目实战

此处假设服务端返回的数据格式为{"code":xxx,"data":T,"msg":""},其中code为响应码,整型,等于200时为成功,其余为失败,data对应的数据类型为泛型(boolean,int,double,String,对象{ },数组[ ]等类型)

{
"code": 200,
"data":T,
"msg": ""
}

对应的Response类为

class TKResponse<T>(val code:Int,val msg: String?, val data: T?) : Serializable {
companion object{
const val STATUS_OK=200
}
fun isSuccess():Boolean{
return code== STATUS_OK
}
}
  • MVC项目

    • 定义MVCHttpCallback,用于将网络请求结果回调给UI界面
    abstract class MVCHttpCallback<T> {
    
        private val type: Type
    
        init {
    val arg = TypeUtil.getType(javaClass)
    type = TypeBuilder
    .newInstance(TKResponse::class.java)
    .addTypeParam(arg)
    .build()
    } fun getType(): Type {
    return this.type
    } /**
    * 请求开始时回调,可以在此加载loading对话框等,默认为空实现
    */
    open fun onStart() {} /**
    * 抽象方法,请求成功回调,返回内容为泛型,对应TKResponse的data
    */
    abstract fun onSuccess(result: T?) /**
    * 抽象方法,请求失败回调,返回内容为code(错误码),msg(错误信息)
    */
    abstract fun onFailure(code: Int, msg: String?) /**
    * 上传进度回调,默认为空实现
    */
    open fun onProgress(readBytes: Long, totalBytes: Long) {} /**
    * 请求完成时回调,请求成功之后才会回调此方法,默认为空实现
    */
    open fun onComplete() {} }
    • 定义网络接口,封装GET/POST等网络请求
    object MVCApi {
    
        /**
    * GET请求
    * context:上下文
    * url:请求url
    * params:参数列表,可为null
    * tag:标识一个网络请求
    * callback:网络请求回调
    */
    inline fun <reified T> httpGet(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null,
    callback: MVCHttpCallback<T>
    ) {
    RxHttp.getInstance().get(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(simpleHttpCallback(callback))
    } /**
    * POST请求
    * context:上下文
    * url:请求url
    * params:参数列表,可为null
    * tag:标识一个网络请求
    * callback:网络请求回调
    */
    inline fun <reified T> httpPost(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null,
    callback: MVCHttpCallback<T>
    ) {
    RxHttp.getInstance().post(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(simpleHttpCallback(callback))
    } ...... inline fun <reified T> simpleHttpCallback(callback: MVCHttpCallback<T>): HttpCallback<TKResponse<T>> {
    return object : HttpCallback<TKResponse<T>>(callback.getType()) {
    override fun onStart() {
    super.onStart()
    callback.onStart()
    } override fun onNext(response: TKResponse<T>?) {
    if (response != null) {
    if (response.isSuccess()) {
    callback.onSuccess(response.data)
    } else {
    return onError(ServerException(response.code, response.msg))
    } } else {
    return onError(NullResponseException(TKErrorCode.ERRCODE_RESPONSE_NULL, TKErrorCode.ERRCODE_RESPONSE_NULL_DESC))
    } } override fun onError(e: Throwable?) {
    handleThrowable(e).run {
    callback.onFailure(first, second)
    }
    } override fun onComplete() {
    super.onComplete()
    callback.onComplete()
    } override fun onProgress(readBytes: Long, totalBytes: Long) {
    super.onProgress(readBytes, totalBytes)
    callback.onProgress(readBytes, totalBytes)
    }
    }
    }
    • 在View层如Activity中调用网络接口
    MVCApi.httpGet(
    context = baseActivity,
    url = TKURL.URL_GET,
    params = null,
    tag = null,
    callback = object : MVCHttpCallback<List<Banner>>() {
    override fun onStart() {
    LogUtils.d(TAG, "onButtonGet onStart() called")
    } override fun onSuccess(result: List<Banner>?) {
    Log.d(TAG, "onButtonGet onSuccess() called with: result = $result")
    } override fun onFailure(code: Int, msg: String?) {
    Log.d(TAG, "onButtonGet onFailure() called with: code = $code, msg = $msg")
    } override fun onComplete() {
    Log.d(TAG, "onButtonGet onComplete() called")
    } })

    具体使用可以参考demo代码,demo中有详细的示例演示MVC项目如何使用RxHttp

  • MVVM项目

    • 定义Activity基类BaseMvvmActivity
    abstract class BaseMvvmActivity<VM : BaseViewModel, VDB : ViewDataBinding> : AppCompatActivity(){
    
       lateinit var viewModel: VM
    lateinit var binding: VDB protected abstract fun getLayoutId(): Int final override fun onCreate(savedInstanceState: Bundle?) {
    onCreateStart(savedInstanceState)
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, getLayoutId())
    binding.lifecycleOwner = this
    createViewModel()
    onCreateEnd(savedInstanceState)
    } protected open fun onCreateStart(savedInstanceState: Bundle?) {}
    protected open fun onCreateEnd(savedInstanceState: Bundle?) {} /**
    * 创建ViewModel
    */
    private fun createViewModel() {
    val type = findType(javaClass.genericSuperclass)
    val modelClass = if (type is ParameterizedType) {
    type.actualTypeArguments[0] as Class<VM>
    } else {
    BaseViewModel::class.java as Class<VM>
    }
    viewModel = ViewModelProvider(this).get(modelClass)
    } private fun findType(type: Type): Type?{
    return when(type){
    is ParameterizedType -> type
    is Class<*> ->{
    findType(type.genericSuperclass)
    }
    else ->{
    null
    }
    }
    } }
    • 定义ViewModel的基类BaseViewModel
    open class BaseViewModel(application: Application) : AndroidViewModel(application) {
    
       /**
    * 网络仓库
    */
    protected val networkbaseRepository: NetworkRepository = NetworkRepository.instance /**
    * 上下文
    */
    protected var context: Context = application.applicationContext }
    • 定义网络仓库,封装网络接口
    /**
    * MVVM架构网络仓库
    * UI->ViewModel->Repository->LiveData(ViewModel)->UI
    */
    class NetworkRepository private constructor() { companion object {
    val instance = NetworkRepository.holder
    } private object NetworkRepository {
    val holder = NetworkRepository()
    } inline fun <reified T> wrapHttpCallback(): MvvmHttpCallback<T> {
    return object : MvvmHttpCallback<T>() { }
    } inline fun <reified T> newCallback(liveData: MutableLiveData<TKState<T>>): HttpCallback<TKResponse<T>> {
    val type = wrapHttpCallback<T>().getType()
    return object : HttpCallback<TKResponse<T>>(type) {
    override fun onStart() {
    liveData.value = TKState.start()
    } override fun onNext(response: TKResponse<T>?) {
    liveData.value = TKState.response(response)
    } override fun onError(e: Throwable?) {
    liveData.value = TKState.error(e)
    } override fun onComplete() { /**
    * 亲,此处不要做任何操作,不要给LiveData赋值,防止onNext对应的LiveData数据被覆盖,
    * 在TKState类handle方法里会特别处理回调的,放心好了
    */
    } override fun onProgress(readBytes: Long, totalBytes: Long) {
    liveData.value = TKState.progress(readBytes, totalBytes)
    }
    }
    } inline fun <reified T> httpGet(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance()
    .get(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } inline fun <reified T> httpPost(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().post(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } inline fun <reified T> httpPostForm(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().postForm(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } inline fun <reified T> httpPut(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().put(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } inline fun <reified T> httpDelete(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().delete(context)
    .params(params)
    .url(url)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } /**
    *上传
    *支持上传多个文件,map中对应的value类型为File类型或Uri类型
    *支持监听上传进度
    val map =Map<String,Any>()
    map.put("model", "xiaomi")
    map.put("os", "android")
    map.put("avatar",File("xxx"))
    map.put("video",uri)
    */
    inline fun <reified T> httpUpload(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().upload(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    } /**
    * 下载
    * context:上下文,如不需要和生命周期绑定,应该传递applicationContext
    * url:下载地址
    * dir:本地目录路径
    * filename:保存文件名称
    * callback:下载进度回调
    * md5:下载文件的MD5值
    * breakpoint:是否支持断点下载,默认为true
    */
    fun httpDownload(context: Context, url: String, dir: String, filename: String, callback: DownloadCallback, md5: String? = null, breakPoint: Boolean = true, tag: Any? = null) {
    RxHttp.getInstance().download(context).dir(dir).filename(filename).breakpoint(breakPoint).md5(md5).url(url).tag(tag).enqueue(callback)
    } }
    • 定义TKState类,用于将网络回调转化为LiveData
    /**
    *将HttpCallback回调转化为对应的LiveData
    */
    class TKState<T> { var state: Int = 0
    var code = TKErrorCode.ERRCODE_UNKNOWN
    var msg: String? = null
    var data: T? = null
    var progress: Long = 0
    var total: Long = 0 @JvmOverloads
    constructor(state: Int, data: T? = null, msg: String? = "") {
    this.state = state
    this.data = data
    this.msg = msg
    } constructor(state: Int, throwable: Throwable?) {
    this.state = state
    handleThrowable(throwable).run {
    this@TKState.code = first
    this@TKState.msg = second
    }
    } constructor(state: Int, progress: Long, total: Long) {
    this.state = state
    this.progress = progress
    this.total = total
    } fun handle(handleCallback: HandleCallback<T>.() -> Unit) {
    val callback = HandleCallback<T>()
    callback.apply(handleCallback)
    when (state) {
    START -> {
    callback.onStart?.invoke()
    }
    SUCCESS -> {
    callback.onSuccess?.invoke(data)
    }
    FAIL -> {
    callback.onFailure?.invoke(code, msg)
    }
    PROGRESS -> {
    callback.onProgress?.invoke(progress, total)
    }
    }
    if (state == SUCCESS || state == FAIL) {
    callback.onComplete?.invoke()
    }
    } open class HandleCallback<T> {
    var onStart: (() -> Unit)? = null
    var onSuccess: ((T?) -> Unit)? = null
    var onFailure: ((Int, String?) -> Unit)? = null
    var onComplete: (() -> Unit)? = null
    var onProgress: ((Long, Long) -> Unit)? = null fun onStart(callback: (() -> Unit)?) {
    this.onStart = callback
    } fun onSuccess(callback: ((T?) -> Unit)?) {
    this.onSuccess = callback
    } fun onFailure(callback: ((Int, String?) -> Unit)?) {
    this.onFailure = callback
    } fun onComplete(callback: (() -> Unit)?) {
    this.onComplete = callback
    } fun onProgress(callback: ((Long, Long) -> Unit)?) {
    this.onProgress = callback
    }
    } companion object {
    const val START = 0
    const val SUCCESS = 1
    const val FAIL = 2
    const val PROGRESS = 3 fun <T> start(): TKState<T> {
    return TKState(START)
    } fun <T> response(response: TKResponse<T>?): TKState<T> {
    if (response != null) {
    if (response.isSuccess()) {
    return TKState(SUCCESS, response.data, null)
    } else {
    return error(ServerException(response.code, response.msg))
    } } else {
    return error(NullResponseException(TKErrorCode.ERRCODE_RESPONSE_NULL, TKErrorCode.ERRCODE_RESPONSE_NULL_DESC))
    } } fun <T> error(t: Throwable?): TKState<T> {
    return TKState(FAIL, t)
    } fun <T> progress(progress: Long, total: Long): TKState<T> {
    return TKState(PROGRESS, progress, total)
    }
    } }
    • 经过一系列封装,最后在View层如Activity中ViewModel调用Repository中的接口
     viewModel.testPost(hashMapOf(
    "name" to "jack",
    "location" to "shanghai",
    "age" to 28)
    )
    .observeState(this) {
    onStart {
    LogUtils.d(TAG, "onButtonPost() onStart called")
    }
    onSuccess {
    LogUtils.d(TAG, "onButtonPost() onSuccess called:${it}")
    }
    onFailure { code, msg ->
    ToastHelper.toast("onButtonPost() onFailure,code:${code},msg:${msg}")
    }
    onComplete {
    LogUtils.d(TAG, "onButtonPost() onComplete called")
    }
    }

    具体使用还要参考demo代码,demo中有详细的示例演示MVVM项目如何使用RxHttp

强烈建议下载Demo代码,Demo中有详细的示例,演示MVVM及MVC架构如何使用RxHttp,如果本文对你有帮助,可以考虑给我点赞哦

Demo

https://github.com/kongpf8848/RxHttp

RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库的更多相关文章

  1. Web Uploader - 功能齐全,完美兼容 IE 的上传组件

    文件上传是网站和 Web 应用程序的常用功能,一直没有一款完美的文件上传组件,因此让很多开发人员碰到头疼的浏览器兼容问题. WebUploader 是由 Baidu FEX 团队开发的一款以 HTML ...

  2. Prism 轻量级可扩展代码高亮库.

    官方网站:http://prismjs.com/ Prism 是一个轻量级并且简单易用的 JavaScript 类库,minified 和 gzipped 压缩后只有 1.5kb 大小,即使添加语言定 ...

  3. Dapper完美兼容Oracle,执行存储过程,并返回结果集。

    Dapper完美兼容Oracle,执行存储过程,并返回结果集. 这个问题,困扰了我整整两天. 刚刚用到Dapper的时候,感觉非常牛掰.特别是配合.net 4.0新特性dynamic,让我生成泛型集合 ...

  4. Picaso完美兼容OkHttp3.3,缓存优化两不误 - Tamic Developer"s Blog

    为何在Fresco,Glide这么强大的背景下,我又想起了当初的Picasso,又为何写这篇文章?是因为最近项目采用了square公司的RxAndroid,Retrfit和OKhttp, 不得不联想到 ...

  5. input输入框的border-radius属性在IE8下的完美兼容

    在工作中我们发现搜索框大部分都是有圆角的,为此作为经验不足的前端人员很容易就想到,给input标签添加border-radius属性不就解决了嘛.不错方法确实是这样,但是不要忘了border-radi ...

  6. 浮出层的css写法,完美兼容IE6~10

    利用元素间的绝对定位差一像素,使用不同颜色做出浮出层小三角的效果,完美兼容各浏览器! html部分: <div class="poptip"> <span cla ...

  7. 【AOS应用基础平台】完好了AOS标签库,和标准标签库完美兼容了

    [金码坊AOS开发平台]今天①完好了AOS标签库,和标准标签库完美兼容了.②新开发了依据子页面动态生成主页面的二级导航菜单功能.#AOS开发平台#

  8. js 完美兼容浏览器的复制功能

    1,js结合swf的复制功能,完美兼容火狐,谷歌,360,ie8,使用示例:(ps:引入copy.swf比较重要,文件传送门 解压密码:http://www.bieanju.com/,为了防止360删 ...

  9. IE6下完美兼容css3圆角和阴影属性的htc插件PIE.htc

    1.(推荐:)css插件PIE.htc,这个才是真正完美兼容css3的圆角和阴影属性在IE6环境下使用的效果,但要注意的是:下面的代码必须写在html文件的head标签内,否则无效(不能从外部引用下面 ...

随机推荐

  1. samba 随笔

    SElinux以及防火墙的关闭 关闭SELinux的方法: 修改/etc/selinux/config文件中的SELINUX="" 为 disabled ,然后重启. 如果不想重启 ...

  2. HarmonyOS应用开发-Component体系介绍(一)

    目录: 1. Component的内部类/接口 2. Component方法简介 3.总结 在HarmonyOS的UI框架中,Component为用户界面提供基本组件,Component类位于ohos ...

  3. Educational Codeforces Round 67 E.Tree Painting (树形dp)

    题目链接 题意:给你一棵无根树,每次你可以选择一个点从白点变成黑点(除第一个点外别的点都要和黑点相邻),变成黑点后可以获得一个权值(白点组成连通块的大小) 问怎么使权值最大 思路:首先,一但根确定了, ...

  4. Codeforces Global Round 11 A. Avoiding Zero(前缀和)

    题目链接:https://codeforces.com/contest/1427/problem/A 题意 将 \(n\) 个数重新排列使得不存在为 \(0\) 的前缀和. 题解 计算正.负前缀和,如 ...

  5. 洛谷P3796

    题目链接  题意:有n个由小写字母组成的模式串以及一个文本串T.每个模式串可能会在文本串中出现多次.哪些模式串在文本串T中出现的次数最多. 题解:ac自动机模板加强版,开一个数组单独记录各个字符串出现 ...

  6. 【uva 120】Stacks of Flapjacks(算法效率--构造法+选择排序思想)

    题意:有N张正在锅里的一叠煎饼,每张都有一个数字,代表其大小.厨师每次可以选择一个数k,把从锅底开始数第k张上面的煎饼全部翻过来,即原来在上面的煎饼现在到了下面.要求设计一种方法使得所有煎饼按照从小到 ...

  7. HDU 3537 Daizhenyang's Coin 翻硬币博弈

    题意: 给你n个硬币,你可以从中拿出来1.2.3个硬币,它们不一定要连续,你只需要保证拿出来的硬币中那个下标最大的硬币一定要是正面朝上,最后谁不能操作,谁就输了 题解: 翻硬币游戏 结论: 局面的SG ...

  8. [POJ 2585] Window Pains 拓朴排序

    题意:你现在有9个2*2的窗口在4*4的屏幕上面,由于这9这小窗口叠放顺序不固定,所以在4*4屏幕上有些窗口只会露出来一部分. 如果电脑坏了的话,那么那个屏幕上的各小窗口叠放会出现错误.你的任务就是判 ...

  9. Dapr微服务应用开发系列3:服务调用构件块

    题记:这篇开始逐一深入介绍各个构件块,从服务调用开始 原理 所谓服务调用,就是通过这个构件块让你方便的通过HTTP或者gRPC协议同步调用其他服务的方法,这些方法也是通过HTTP或者gRPC来暴露的. ...

  10. Nginx 服务介绍

    目录 静态 / 动态 Web 服务 Nginx 简介 Nginx 的优点 Nginx 和 Apache 的比较 Nginx 的安装 Nginx 相关文件 Nginx 主配置文件 Nginx 虚拟主机配 ...