我正在开发一个考试项目。我使用 Akka HTTP 创建了一个服务器并使用 postman 进行了尝试。一切正常。但是当我尝试使用 Flutter 发送请求时(顺便说一句,这是我第一次使用它),它给了我这个错误:
Connection failed (OS Error: Operation not permitted, errno = 1), address = localhost, port = 8080, uri=http://localhost:8080/friends_avg
下面我给你留下我的服务器,我使用http请求的文件和info.plist文件。
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors
import ch.megard.akka.http.cors.scaladsl.settings.CorsSettings
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.ExceptionHandler
object Server {
def customExceptionHandler: ExceptionHandler = ExceptionHandler {
case exception: Exception => // Puoi specificare il tipo di eccezione che vuoi gestire
extractUri { uri =>
complete(StatusCodes.InternalServerError, s"Si è verificato un errore durante l'elaborazione della richiesta: ${exception.getMessage}")
}
}
val corsSettings: CorsSettings = CorsSettings.defaultSettings.withAllowGenericHttpRequests(true)
case class numUsersResponse(numUsers: Long)
case class numFriendshipsResponse(numFriendships: Long)
case class numAvgFriendsResponse(numAvgFriends: Double)
case class FriendsListResponse(count: Long, friendsList: List[Long])
case class CommonFriendsResponse(friends: List[Long])
case class CountGroupsResponse(count: Long, groupIds: List[Long])
case class GroupsUserResponse(userIds: List[Long])
case class CommonGroupResponse(groupIds: List[Long])
case class MostPopularGroupResponse(groupId: Long, userIds: List[Long])
case class PopularNGroupsResponse(groupIds: List[Long])
// Define JSON formats for the response case classes
implicit val numUsersResponseFormat = jsonFormat1(numUsersResponse)
implicit val numFriendshipsResponseFormat = jsonFormat1(numFriendshipsResponse)
implicit val numAvgFriendsResponseFormat = jsonFormat1(numAvgFriendsResponse)
implicit val friendsListResponseFormat = jsonFormat2(FriendsListResponse)
implicit val commonFriendsResponseFormat = jsonFormat1(CommonFriendsResponse)
implicit val countGroupsResponseFormat = jsonFormat2(CountGroupsResponse)
implicit val groupsUserResponseFormat = jsonFormat1(GroupsUserResponse)
implicit val commonGroupResponseFormat = jsonFormat1(CommonGroupResponse)
implicit val mostPopularGroupResponseFormat = jsonFormat2(MostPopularGroupResponse)
implicit val popularNGroupsResponseFormat = jsonFormat1(PopularNGroupsResponse)
val numUser: Route =
path("num_users") {
get {
cors() {
complete(numUsersResponse(Queries.numUsers()))
}
}
}
val numFriendships: Route =
path("num_friendships") {
get {
cors() {
complete(numFriendshipsResponse(Queries.numFriendships()))
}
}
}
val most_popular: Route =
path("most_popular") {
cors() {
get {
parameters(Symbol("nUsers").as[Int]) { nUsers =>
complete(Queries.most_popular(nUsers))
}
}
}
}
val least_popular: Route =
path("least_popular") {
cors() {
get {
parameters(Symbol("nUsers").as[Int]) { nUsers =>
complete(Queries.least_popular(nUsers))
}
}
}
}
val friends_list: Route =
path("friends_list") {
cors() {
get {
parameters(Symbol("id").as[Long]) { id =>
complete(Queries.friends_list(id))
}
}
}
}
val commonFriends: Route =
path("common_friends") {
cors() {
get {
parameters(Symbol("id1").as[Long], Symbol("id2").as[Long]) { (id1, id2) =>
complete(Queries.commonFriends(id1, id2))
}
}
}
}
val countGroups: Route =
path("count_groups") {
cors() {
get {
parameters(Symbol("user_id").as[Int]) { id =>
complete(Queries.countGroups(id))
}
}
}
}
val groupsUser: Route =
path("groups_user") {
cors() {
get {
parameters(Symbol("id").as[Long]) { id =>
complete(Queries.groupsUser(id))
}
}
}
}
val commonGroup: Route =
path("common_group") {
cors() {
get {
parameters(Symbol("id1").as[Int], Symbol("id2").as[Int]) { (id1, id2) =>
complete(Queries.commonGroup(id1, id2))
}
}
}
}
val mostPopularGroup: Route =
path("most_popular_group") {
cors() {
get {
complete(Queries.mostPopularGroup())
}
}
}
val popularN_Group: Route =
path("popularN_Groups") {
cors() {
get {
parameters(Symbol("n").as[Int]) { n =>
complete(Queries.popularN_Group(n))
}
}
}
}
val friendAvg: Route =
path("friends_avg") {
get {
cors() {
complete(numAvgFriendsResponse(Queries.friendAvg()))
}
}
}
def route :Route= cors(corsSettings){
concat(numUser,numFriendships, most_popular,least_popular, friends_list, commonFriends, countGroups, groupsUser, commonGroup,
mostPopularGroup, popularN_Group,friendAvg )
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:friendster_project_frontend/pagine/home.dart';
import 'package:http/http.dart' as http;
//------------------------- SEZIONE QUERY E HTTP-------------------------------//
//numero utenti
/*
Future indica una chiamata futura che riceverà un stringa;
async indica che la chiamata è asincrona, quindi devo aspettare il risultato della chiamata http
*/
Future<int> getNumeroUtenti() async {
var response = await http.get(Uri.parse('http://localhost:8080/friends_avg'));
if (response.statusCode == 200) {
// If the server returns a successful response, parse the JSON
var data = json.decode(response.body);
int numUsers = data['numUsers'];
return numUsers;
} else {
// If the server did not return a successful response, throw an exception.
throw Exception('Failed to load data');
}
}
//-----------------------------------------------//
class UserPage extends StatefulWidget {
const UserPage({super.key});
@override
State<UserPage> createState() => _UserPageState();
}
class _UserPageState extends State<UserPage>{
//variabili che otteniamo con le chiamate http
late Future<int> numeroUtenti;
@override
void initState(){
super.initState();
numeroUtenti = getNumeroUtenti(); //appena apro la pagina ottengo il numero di utenti
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: numeroUtenti,
builder: (context,snapshot){
if(snapshot.hasData){
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Numero utenti:'),
Text(
snapshot.data!.toString(),
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
ElevatedButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute<void>(builder: (context) => const Home()));
},
child: const Text('Torna alla Home'),
),
],
),
);
}
else if(snapshot.hasError){
return Center(child: Text("Erorre nella richiesta ${snapshot.error}") ,);
}
return const CircularProgressIndicator();
},
),
);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>com.apple.security.network.client</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>$(PRODUCT_COPYRIGHT)</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
我正在使用 VS 代码
我想添加
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>com.apple.security.network.client</key>
<true/>
就足够了,因为每个人都说我只需要添加这行代码。