Android 应用无法连接到本地主机服务
Android app unable to connect to localhost service
我是 android 应用程序开发的新手。我已经创建了一个简单的 hello world android 应用程序,我正在尝试在我的本地计算机上调用 HelloWorldService
运行 的 REST api 端点。该服务是 运行 使用 Spring 在 IntelliJ 中启动。服务代码如下:
@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();
}
});
});
}
我试过什么?
- 谷歌搜索后,我明白我不能使用
localhost
作为访问网络服务的IP地址,我必须使用实际的网络IP。此外,笔记本电脑和 phone 需要在同一网络上。因此,我更新了我的基础 url 以使用 inet 地址 x.x.x.x:port_number
.
- 我已确认两个设备都连接到同一个 Wi-Fi。
- 我已经为我的 android 应用程序授予互联网权限。
<uses-permission android:name="android.permission.INTERNET" />
- 在笔记本电脑上尝试过 postman 和 web 浏览器。我得到了正确的回应。
- 尝试使用移动浏览器调用服务。我无法访问它。
- 使用了特殊地址的模拟器
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)
感谢任何指点。
如果你是 运行 模拟器上的 android 应用程序,你可以只使用 10.0.2.2 的 ip 默认情况下,这是指模拟器的主机。
如果您使用的是真实设备,请使用真实 IP。这意味着服务器要么需要在 saw WIFI 网络上并且必须设置网络防火墙以允许流量进入,要么您需要一个可公开寻址的 IP 地址。大多数路由器默认设置 NAT,因此您必须在其中挖一个洞。
此外,请确保服务器使用正确的 IP 地址,而不只是绑定到本地主机。
我是 android 应用程序开发的新手。我已经创建了一个简单的 hello world android 应用程序,我正在尝试在我的本地计算机上调用 HelloWorldService
运行 的 REST api 端点。该服务是 运行 使用 Spring 在 IntelliJ 中启动。服务代码如下:
@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();
}
});
});
}
我试过什么?
- 谷歌搜索后,我明白我不能使用
localhost
作为访问网络服务的IP地址,我必须使用实际的网络IP。此外,笔记本电脑和 phone 需要在同一网络上。因此,我更新了我的基础 url 以使用 inet 地址x.x.x.x:port_number
. - 我已确认两个设备都连接到同一个 Wi-Fi。
- 我已经为我的 android 应用程序授予互联网权限。
<uses-permission android:name="android.permission.INTERNET" />
- 在笔记本电脑上尝试过 postman 和 web 浏览器。我得到了正确的回应。
- 尝试使用移动浏览器调用服务。我无法访问它。
- 使用了特殊地址的模拟器
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)
感谢任何指点。
如果你是 运行 模拟器上的 android 应用程序,你可以只使用 10.0.2.2 的 ip 默认情况下,这是指模拟器的主机。
如果您使用的是真实设备,请使用真实 IP。这意味着服务器要么需要在 saw WIFI 网络上并且必须设置网络防火墙以允许流量进入,要么您需要一个可公开寻址的 IP 地址。大多数路由器默认设置 NAT,因此您必须在其中挖一个洞。
此外,请确保服务器使用正确的 IP 地址,而不只是绑定到本地主机。