【问题标题】:Android app unable to connect to localhost serviceAndroid 应用无法连接到 localhost 服务
【发布时间】:2021-10-30 08:55:09
【问题描述】:

我是 Android 应用程序开发的新手。我创建了一个简单的 hello world android 应用程序,我正在尝试调用在我的本地计算机上运行的 HelloWorldService 的 REST api 端点。该服务使用 IntelliJ 中的 Spring Boot 运行。服务代码如下:

@RestController
public class SimpleController {
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String sayHello() {
        return "Hello world";
    }
}

要从移动应用程序调用此 api,我使用的是 Retrofit 库。代码如下:

依赖关系

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

    compileOnly 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'

SimpleService.java

public interface SimpleService {
    @GET("/hello")
    Call<String> sayHello();
}

MainActivity.java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        TextView textView = findViewById(R.id.textView);

        button.setOnClickListener(view -> {
            OkHttpClient httpClient = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .build();

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://x.x.x.x:8080")
                    .client(httpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            final SimpleService simpleService = retrofit.create(SimpleService.class);
            final Call<String> stringCall = simpleService.sayHello();

            stringCall.enqueue(new Callback<String>() {
                @Override
                public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
                    textView.setText(response.body());
                }

                @Override
                public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
                    t.printStackTrace();
                }
            });
        });
    }

我尝试了什么?

  1. 谷歌搜索后,我了解到我不能使用localhost作为访问网络服务的IP地址,我必须使用实际的网络IP。此外,笔记本电脑和手机需要在同一个网络上。因此,我更新了我的基本 url 以使用 inet 地址x.x.x.x:port_number
  2. 我已验证两台设备都连接到同一个 wi-fi。
  3. 我已授予我的 Android 应用程序的互联网权限。 &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
  4. 在笔记本电脑中尝试过邮递员和网络浏览器。我得到了正确的答复。
  5. 尝试使用移动浏览器调用服务。我无法访问它。
  6. 使用了特殊地址10.0.2.2的模拟器,我可以访问它。

但是,我无法连接到端点并收到以下错误:

W/System.err: java.net.SocketTimeoutException: failed to connect to /192.168.0.11 (port 8080) from /192.168.0.26 (port 56860) after 120000ms
W/System.err:     at libcore.io.IoBridge.connectErrno(IoBridge.java:191)
        at libcore.io.IoBridge.connect(IoBridge.java:135)
W/System.err:     at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
W/System.err:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
        at java.net.Socket.connect(Socket.java:621)
        at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:71)
        at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:263)
W/System.err:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:183)
        at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
        at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
        at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
        at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
W/System.err:     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
W/System.err:     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
W/System.err:     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:172)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)

感谢任何指针。

【问题讨论】:

  • 您应该能够通过使用邮递员甚至您的浏览器来测试它是否与服务有关,以查看 url 是否通过它们给出错误。可能是您的计算机阻止了连接
  • 是的,我对此进行了测试,邮递员和网络浏览器都可以正常工作。我可以使用它们访问服务。
  • 在您的 Android 设备上使用浏览器。
  • 不要将您的服务器绑定到本地 ip 或 127.0.0.1。根本不要绑定。

标签: android spring-boot rest retrofit2


【解决方案1】:

如果你在模拟器上运行安卓应用,你可以使用 10.0.2.2 的 ip 默认情况下,这是指模拟器的主机。

如果您使用的是真实设备,请使用真实 IP。这意味着服务器要么需要在 WIFI 网络上,并且必须设置网络防火墙以允许访问它,或者您需要一个可公开寻址的 IP 地址。大多数路由器默认设置 NAT,所以你必须在其中戳一个洞。

另外,请确保服务器使用正确的 IP 地址并且不只是绑定到 localhost。

【讨论】:

  • 是的,我可以在模拟器上运行。我正在尝试在真实设备上运行。设备(手机和笔记本电脑)都连接到同一个 wifi。我正在使用 Netgear 路由器,没有看到任何阻塞服务。
  • @VishalBhavsar 您的路由器没有运行防火墙的可能性为 0。这是 20 年来路由器的默认设置。您需要在其中戳一个洞,以便任何设备在该网络上相互通信。
  • 嗨@gabe-sechan,我正在使用NetGear C3700-100NAS路由器。从各种论坛中,我了解到其门户中的“阻止服务”选项用于防火墙。该选项设置为“从不”。环顾四周后,我可以通过为我的笔记本电脑分配静态地址来访问 Web 服务。感谢您的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-03
  • 2020-07-14
  • 2017-11-10
  • 2023-03-28
  • 2015-02-03
相关资源
最近更新 更多