返回顶部
首页 > 资讯 > 精选 >Android OkHttp代理与路由怎么应用
  • 915
分享到

Android OkHttp代理与路由怎么应用

2023-07-05 11:07:04 915人浏览 安东尼
摘要

本文小编为大家详细介绍“Android OkHttp代理与路由怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android OkHttp代理与路由怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一

本文小编为大家详细介绍“Android OkHttp代理与路由怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android OkHttp代理与路由怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

代理

OkHttp 支持设置代理,使用OkHttpClient.proxy()即可设置。

什么是代理?

  • 根据代理的对象不同,可分为正向代理和反向代理。正向代理代理的是客户端,负责接收客户端的请求转发到目标服务器,并将结果返回给客户端。反向代理代理的是服务端,服务端将反向代理看做客户端。

  • 正向代理一般用于突破访问限制(如访问外网),提高访问速度。反向代理则用于负载均衡(如Nginx),资源防护。

  • 正向代理服务器部署在客户端侧,反向代理服务器部署在服务端侧。

  • 使用正向代理,目标服务器对客户端来说是透明的,客户端将代理服务器看做是目标服务器。

  • 使用反向代理,客户端对目标服务器来说的透明的,目标服务器将代理服务器看做是客户端。

代理的类型

根据代理服务器使用代理协议的不同,可分为 Http 代理,Http Tunnel(隧道)代理,Socks 代理。3种代理协议的实现原理各有不同,读者可自行查找相关资料了解。

Http 代理:我们知道若一个请求直接发送到目标服务器时,请求行中只会包含相对路径的 URL (完整 URL 的 path 部分)。而一个请求发送到 http 代理服务器,要求它请求行的url为绝对路径,这遵循了 www.ietf.org/rfc/rfc2616… 5.1.2小节标准的规定。

Http Tunnel 代理:也称为 Http 隧道代理,最早在 www.ietf.org/rfc/rfc2817… 5.1 小节定义,隧道代理的出现为了让代理服务器能跑 https 的流量。隧道代理需要客户端首先发送一个请求方法为CONNECT 的报文,请求隧道代理创建一条到达任意目的服务器和端口的 tcp 连接,并对客户端和目的服务器之间的后继数据进行原样转发。

Socks 代理:Socks 是最常见的代理服务协议,服务通常使用 1080 端口。Socks 代理与其他类型的代理不同,它只是简单地传递数据包,而并不关心是何种应用协议,所以 Socks 代理服务器比其他类型的代理服务器速度要快得多。Socks 代理又分为 Socks4 和 Socks5,二者不同的是 Socks4 代理只支持 TCP 协议,而 Socks5 代理则既支持 TCP 协议又支持 UDP 协议,还支持各种身份验证机制、服务器端域名解析等。

早在 jdk 1.5中就提供了一个Proxy类来表示代理。

public class Proxy {    // 代理类型    public enum Type {        // 不使用代理,直连目标服务器        DIRECT,        // HTTP 协议代理        HTTP,        // SOCKS 协议代理        SOCKS    };    // 代理类型    private Type type;    // 代理的 IP 套接字地址(IP + 端口号)    private SocketAddress sa;    public final static Proxy NO_PROXY = new Proxy();    // 默认不使用代理    private Proxy() {        type = Type.DIRECT;        sa = null;    }}

代理选择器

jdk 提供了一个名为ProxySelector的类,意为“代理选择器”。ProxySelector是个抽象类,继承它的类需要实现selectconnectFailed方法,这说明我们可通过继承ProxySelector自定义代理选择器,在select方法中返回自定义的代理列表。而当一个代理服务器无法连接时,调用connectFailed方法通知代理选择器当前代理服务器不可用。如下代码,ProxySelector的静态代码块中使用Class对象的newInstance方法创建了一个DefaultProxySelector的对象。

public abstract class ProxySelector {    private static ProxySelector theProxySelector;    // 创建 DefaultProxySelector 对象    static {        try {            Class<?> c = Class.forName("sun.net.spi.DefaultProxySelector");            if (c != null && ProxySelector.class.isAssignableFrom(c)) {                theProxySelector = (ProxySelector) c.newInstance();            }        } catch (Exception e) {            theProxySelector = null;        }    }    public static ProxySelector getDefault() {        SecurityManager sm = System.getSecurityManager();        if (sm != null) {            sm.checkPermission(SecurityConstants.GET_PROXYSELECTOR_PERMISSION);        }        return theProxySelector;    }    public abstract List<Proxy> select(URI uri);    public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe);}

ProxySelector有个两个子类DefaultProxySelectorNullProxySelector

DefaultProxySelector:jdk 中提供的代理选择器,也是 OkHttp 默认使用的代理选择器,select返回系统设置的代理列表。

NullProxySelector:OkHttp 中提供的代理选择器,select返回的代理列表只包含一个NO_PROXY,即不使用代理。

在 OkHttp 中可以使用OkHttpClient.proxy(proxy)设置代理,也可以使用OkHttpClient.proxySelector设置代理选择器。OkHttp 会优先使用设置的代理去连接代理服务器,而不是从代理列表中选择。如下代码, OkHttpClient默认使用DefaultProxySelector代理选择器,除非getDefault返回null,才使用NullProxySelector

public Builder() {  proxySelector = ProxySelector.getDefault();  if (proxySelector == null) {    proxySelector = new NullProxySelector();  }}

路由

什么是路由?

在 OkHttp 中,路由表示一个请求到目标服务器或代理服务器的具体路线。对于一个请求来说,如果它的url是域名,经过 DNS 解析之后可能会对应多个 IP 地址,这意味着一个请求到达服务器的路由就有多个

Android OkHttp代理与路由怎么应用

如下程序在我本机环境下使用InetAddress类解析baidu.com这个域名,IP 地址就有两个。

public void domainResolution() throws UnknownHostException {    InetAddress[] inetAddresses = InetAddress.getAllByName("baidu.com");    for (InetAddress inetAddress : inetAddresses) {        System.out.println(inetAddress.toString());    }}

 baidu.com/39.156.66.10
baidu.com/110.242.68.66

OkHttp 会选择其中一个路由来建立到服务器的连接。Route类描述了一个路由应该包含的信息:配置信息,代理信息,代理或目标服务器地址,是否使用 Http 隧道代理。

public final class Route {  // 与目标服务器建立连接所需要的配置信息,包括目标主机名、端口、dns 等  final Address address;  // 该路由的代理信息  final Proxy proxy;  // 代理服务器或目标服务器的地址  final InetSocketAddress inetSocketAddress;  // 该路由是否使用 Http 隧道代理  public boolean requiresTunnel() {    return address.sslSocketFactory != null && proxy.type() == Proxy.Type.HTTP;  }  }

路由数据库

路由数据库是一个路由黑名单库,存储了那些连接到特定 IP 地址或代理服务器失败的路由。这样在创建新的连接时,就可以避免使用这些路由。RouteDatabase类如下。

  • 内部使用 Set 结构来存储路由,保证数据不重复。

  • failed方法将失败的路由加入到 Set 中。

  • connected方法表示该路由连接成功,将它从 Set 中移除。

  • shouldPostpone方法用于判断该路由是否在黑名单中。

final class RouteDatabase {  private final Set<Route> failedRoutes = new LinkedHashSet<>();    public synchronized void failed(Route failedRoute) {    failedRoutes.add(failedRoute);  }    public synchronized void connected(Route route) {    failedRoutes.remove(route);  }    public synchronized boolean shouldPostpone(Route route) {    return failedRoutes.contains(route);  }}

路由选择器

RouteSelector是 OkHttp 中的路由选择器,它的next方法可以返回一个合适的路由集合(Selection)用于连接目标服务器。它的整体工作流程如下所示。

Android OkHttp代理与路由怎么应用

RouteSelector 内部类 Selection

Selection表示被next方法选中的路由集合。内部有一个路由列表和下一个路由的索引

public static final class Selection {    // 路由列表    private final List<Route> routes;    // 下一个路由的索引    private int nextRouteIndex = 0;    Selection(List<Route> routes) {      this.routes = routes;    }    // 是否有下一个路由    public boolean hasNext() {      return nextRouteIndex < routes.size();    }    // 返回下一个路由    public Route next() {      if (!hasNext()) {        throw new NoSuchElementException();      }      return routes.get(nextRouteIndex++);    }    // 返回路由列表    public List<Route> getAll() {      return new ArrayList<>(routes);    }}

RouteSelector 成员变量

  • address:目标服务器地址信息,包括 url,dns,端口信息等。

  • routeDatabase:路由黑名单库

  • call:Call 对象

  • eventListener:Http 请求事件监听器

  • proxies:代理列表

  • nextProxyIndex:下一个代理的索引

  • inetSocketAddresses:用于连接代理或目标服务器可用的地址列表

  • postponedRoutes:不可用的路由列表

private final Address address;private final RouteDatabase routeDatabase;private final Call call;private final EventListener eventListener;private List<Proxy> proxies = Collections.emptyList();private int nextProxyIndex;private List<InetSocketAddress> inetSocketAddresses = Collections.emptyList();private final List<Route> postponedRoutes = new ArrayList<>();

RouteSelector 成员方法

// 初始化代理列表private void resetNextProxy(HttpUrl url, Proxy proxy);// 是否有下一个代理private boolean hasNextProxy();// 是否含有路由可以尝试连接public boolean hasNext();// 初始化连接代理或目标服务器的地址列表private void resetNextInetSocketAddress(Proxy proxy) throws IOException;// 返回代理列表中下一个代理private Proxy nextProxy() throws IOException;// 返回路由集合public Selection next() throws IOException;

resetNextProxy-初始化代理列表

resetNextProxy是个私有方法,在RouteSelector类的构造函数内被调用,用于初始化代理列表。前文我们说过,若OkHttpClient设置了代理,则仅会使用这1个代理。而若没有设置代理则会从代理选择器获取代理列表。resetNextProxy方法的实现正遵循这样的规则。

private void resetNextProxy(HttpUrl url, Proxy proxy) {    // 若设置了代理,仅使用这一个代理    if (proxy != null) {      // If the user specifies a proxy, try that and only that.      proxies = Collections.singletonList(proxy);    } else {      // 若没有设置代理,则调用代理选择器的 select 方法获取代理列表      // Try each of the ProxySelector choices until one connection succeeds.      List<Proxy> proxiesOrNull = address.proxySelector().select(url.uri());      // 若 select 返回的代理列表为空,认为不使用代理,以 Proxy.NO_PROXY 初始化      proxies = proxiesOrNull != null && !proxiesOrNull.isEmpty()          ? Util.immutableList(proxiesOrNull)          : Util.immutableList(Proxy.NO_PROXY);    }    nextProxyIndex = 0;}

hasNextProxy-是否还有代理

hasNextProxy返回代理列表中是否还有下一个代理用于连接。

private boolean hasNextProxy() {return nextProxyIndex &lt; proxies.size();}

hasNext-是否还有路由集合

public boolean hasNext() {return hasNextProxy() || !postponedRoutes.isEmpty();}

resetNextInetSocketAddress-初始化地址列表

resetNextInetSocketAddress用于初始化地址列表,这个地址列表是通往代理服务器或目标服务器的,这取决于所使用的代理类型。

  • 对于DIRECT(直连)和SOCKS类型的代理来说,会使用目标服务器的主机名和端口号。而HTTP类型的代理则会使用代理服务器的主机名和端口号。

  • SOCKS 类型的代理只会生成一个通往目标服务器的地址。

  • 直连类型的代理,经 DNS 解析目标服务器主机名后,可能生成多个通往目标服务器的地址。

  • HTTP 类型的代理,经 DNS 解析目标服务器主机名后,可能生成多个通往代理服务器的地址。

private void resetNextInetSocketAddress(Proxy proxy) throws IOException {    // Clear the addresses. Necessary if getAllByName() below throws!    inetSocketAddresses = new ArrayList<>();    // 主机名    String socketHost;    // 端口号    int socketPort;    // 若代理类型为直连或 SOCKS,则使用目标服务器的主机名和端口号    if (proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.SOCKS) {      socketHost = address.url().host();      socketPort = address.url().port();    } else {      // 若代理类型为 HTTP,则使用代理服务器的主机名和端口号      SocketAddress proxyAddress = proxy.address();      if (!(proxyAddress instanceof InetSocketAddress)) {        throw new IllegalArgumentException(            "Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass());      }      InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;      socketHost = getHostString(proxySocketAddress);      socketPort = proxySocketAddress.getPort();    }    if (socketPort < 1 || socketPort > 65535) {      throw new SocketException("No route to " + socketHost + ":" + socketPort          + "; port is out of range");    }    // SOCKS 类型的代理只会生成一个通往目标服务器的地址    if (proxy.type() == Proxy.Type.SOCKS) {      inetSocketAddresses.add(InetSocketAddress.createUnresolved(socketHost, socketPort));    } else {      eventListener.dnsStart(call, socketHost);      // Try each address for best behavior in mixed IPv4/IPv6 environments.      List<InetAddress> addresses = address.dns().lookup(socketHost);      if (addresses.isEmpty()) {        throw new UnknownHostException(address.dns() + " returned no addresses for " + socketHost);      }      eventListener.dnsEnd(call, socketHost, addresses);      for (int i = 0, size = addresses.size(); i < size; i++) {        InetAddress inetAddress = addresses.get(i);        inetSocketAddresses.add(new InetSocketAddress(inetAddress, socketPort));      }    }}

nextProxy-返回代理列表中下一个代理

nextProxy会从代理列表中取出一个代理返回,同时会调用resetNextInetSocketAddress方法传入当前取出的代理,根据这个代理来初始化地址列表。一个代理对应一个地址列表。

private Proxy nextProxy() throws IOException {    if (!hasNextProxy()) {      throw new SocketException("No route to " + address.url().host()          + "; exhausted proxy configurations: " + proxies);    }    Proxy result = proxies.get(nextProxyIndex++);    resetNextInetSocketAddress(result);    return result;}

next-返回路由集合

nextRouteSelector类中最重要的方法,供外部调用。包含了路由选择器一次完整的工作流程。

public Selection next() throws IOException {    // 若没有路由集合了,抛出异常    if (!hasNext()) {      throw new NoSuchElementException();    }    // Compute the next set of routes to attempt.    List<Route> routes = new ArrayList<>();// 循环直到没有代理可用    while (hasNextProxy()) {      // Postponed routes are always tried last. For example, if we have 2 proxies and all the      // routes for proxy1 should be postponed, we'll move to proxy2. Only after we've exhausted      // all the Good routes will we attempt the postponed routes.      // 从代理列表中取出一个代理      Proxy proxy = nextProxy();      // 遍历该代理对应的地址列表      for (int i = 0, size = inetSocketAddresses.size(); i < size; i++) {        // 创建该地址对应的路由        Route route = new Route(address, proxy, inetSocketAddresses.get(i));        // 若该路由在黑名单,则添加到 postponedRoutes        if (routeDatabase.shouldPostpone(route)) {          postponedRoutes.add(route);        } else {        // 否则添加到 routes          routes.add(route);        }      }      // 若该代理对应的地址列表不为空,退出循环      if (!routes.isEmpty()) {        break;      }    }// 若所有代理的地址列表均为空,则尝试使用黑名单中的路由    if (routes.isEmpty()) {      // We've exhausted all Proxies so fallback to the postponed routes.      routes.addAll(postponedRoutes);      postponedRoutes.clear();    }// 返回路由集合    return new Selection(routes);}

读到这里,这篇“Android OkHttp代理与路由怎么应用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

--结束END--

本文标题: Android OkHttp代理与路由怎么应用

本文链接: https://lsjlt.com/news/351248.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android OkHttp代理与路由怎么应用
    本文小编为大家详细介绍“Android OkHttp代理与路由怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android OkHttp代理与路由怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一...
    99+
    2023-07-05
  • Laravel路由与MVC怎么应用
    这篇文章主要讲解了“Laravel路由与MVC怎么应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Laravel路由与MVC怎么应用”吧!1、路由路由的作用就是将用户的不同url请求转发给...
    99+
    2023-07-04
  • AndroidOkHttp代理与路由的彻底理解
    目录代理什么是代理?代理的类型代理选择器路由什么是路由?路由数据库路由选择器RouteSelector 内部类 SelectionRouteSelector 成员变量Rou...
    99+
    2023-03-09
    Android OkHttp代理路由 Android OkHttp
  • Android中OKHttp怎么使用
    OKHttp是一个开源的HTTP客户端库,用于在Android中发送和接收网络请求。下面是一个示例,展示了如何在Android中使用...
    99+
    2023-09-13
    Android
  • SAP UI5应用里的页面路由怎么处理
    本篇内容主要讲解“SAP UI5应用里的页面路由怎么处理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SAP UI5应用里的页面路由怎么处理”吧!选择SAP UI5应用的webapp文件夹,右键...
    99+
    2023-06-04
  • tp6多应用路由设置与访问
    多应用安装 composer require topthink/think-multi-app 安装完我们在app目录下创建几个应用目录,分别为admin,api,mobile 创建多应用目录之后我...
    99+
    2023-09-10
    php ThinkPHP tp6
  • IIS7应用程序请求路由(arr反向代理)与托管模块结合
    IIS7应用程序请求路由(ARR)是一种反向代理工具,用于将传入的请求路由到后端的多个服务器上。托管模块是一种在IIS中扩展功能的方...
    99+
    2023-09-26
    IIS7
  • PHP的路由与伪静态如何应用
    这篇文章主要介绍“PHP的路由与伪静态如何应用”,在日常操作中,相信很多人在PHP的路由与伪静态如何应用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP的路由与伪静态如何应用”的疑惑有所帮助!接下来,请跟...
    99+
    2023-07-04
  • vue-route路由管理怎么安装与配置
    这篇文章主要介绍“vue-route路由管理怎么安装与配置”,在日常操作中,相信很多人在vue-route路由管理怎么安装与配置问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2024-04-02
  • vue路由怎么用
    这篇文章给大家分享的是有关vue路由怎么用的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构...
    99+
    2024-04-02
  • ASP.NET MVC中的路由原理与用法
    目录一、概述二、路由原理1、注册路由2、路由匹配2.1、匹配方式一2.2、匹配方式二2.3、匹配方式三3、URL参数默认值3.1、参数默认值一3.2、参数默认值二3.4、参数默认值三...
    99+
    2024-04-02
  • Android怎么编写Router路由框架
    本文小编为大家详细介绍“Android怎么编写Router路由框架”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android怎么编写Router路由框架”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。路由是现如...
    99+
    2023-07-06
  • Node.js 路由与 RESTful API:构建现代且可扩展的应用程序
    路由 路由机制用于将客户端请求映射到相应的处理函数。Node.js 提供了 Express 等流行框架,用于简化路由配置: const express = require("express"); const app = express()...
    99+
    2024-04-02
  • VUE 嵌套路由与 SPA:构建现代化单页面应用程序
    在现代 Web 开发中,单页面应用程序 (SPA) 变得越来越流行。与传统的多页面应用程序不同,SPA 仅加载一个 HTML 页面,并通过 JavaScript 动态加载和呈现内容。这提供了无缝的用户体验,无需重新加载页面。 Vue.js...
    99+
    2024-04-02
  • Android中怎么利用OKHTTP实现单例
    本篇文章为大家展示了Android中怎么利用OKHTTP实现单例,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Android OKHTTP的单例和再封装的实例public class&nb...
    99+
    2023-05-30
    android okhttp
  • vue3路由hash与History怎么设置
    本篇内容介绍了“vue3路由hash与History怎么设置”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!vue3路由hash与Histor...
    99+
    2023-07-06
  • Node.js 路由与缓存:改善应用程序响应时间
    路由优化 使用快速路由器: Express 或 Fastify 等快速路由器可以处理大量并发的 HTTP 请求,从而减少响应时间。 减少层叠的路由:避免在路由中使用过多的嵌套,因为这会增加查找特定路由所需的时间。 使用路由组:将相关的路...
    99+
    2024-04-02
  • Flutter路由管理代码这么长怎么高效解决
    这篇文章给大家介绍Flutter路由管理代码这么长怎么高效解决,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。01  背景在Flutter的业务开发过程中,Flutter侧会逐渐丰富自己的路由管理。一...
    99+
    2023-06-04
  • AngularJS中路由怎么用
    这篇文章主要介绍了AngularJS中路由怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体如下:目前的理解中,这个NG的路由模块可以...
    99+
    2024-04-02
  • Vue路由怎么使用
    这篇文章主要介绍“Vue路由怎么使用”,在日常操作中,相信很多人在Vue路由怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue路由怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!在Vue中...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作