1.请求配置类
//
// SFRequestConfig.h
// template
//
// Created by shefeng on 2024/6/20.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SFRequestConfig : NSObject
/**
* 是否允许无效的证书
*/
@property (assign, nonatomic) BOOL allowInvalidCertificates;
/**
* 超时时间
*/
@property (assign, nonatomic) NSInteger timeoutInterval;
/**
* 是否允许无效的证书
*/
@property (assign, nonatomic) BOOL validatesDomainName;
/**
* 可接收的ContentType类型
*/
@property (strong, nonatomic) NSSet <NSString *> *acceptableContentTypes;
/**
* 单例
*/
+ (instancetype)sharedConfig;
@end
NS_ASSUME_NONNULL_END
//
// SFRequestConfig.m
// template
//
// Created by shefeng on 2024/6/20.
//
#import "SFRequestConfig.h"
@implementation SFRequestConfig
+ (instancetype)sharedConfig{
static dispatch_once_t onceToken;
static SFRequestConfig *instance;
dispatch_once(&onceToken, ^{
instance = [[SFRequestConfig alloc] init];
});
return instance;
}
- (NSSet<NSString *> *)acceptableContentTypes{
if (_acceptableContentTypes == nil) {
_acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"image/jpeg",@"image/png",@"text/plain",@"application/json",nil];
}
return _acceptableContentTypes;
}
@end
2.响应配置类
//
// SFResponseConfig.h
// template
//
// Created by shefeng on 2024/6/24.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SFResponseConfig : NSObject
/**
* code的key
*/
@property (strong, nonatomic) NSString *codeKey;
/**
* data的key
*/
@property (strong, nonatomic) NSString *dataKey;
/**
* message的key
*/
@property (strong, nonatomic) NSString *messageKey;
/**
* 成功的状态码
*/
@property (strong, nonatomic) NSNumber *successedCode;
/**
* 失败的状态码
*/
@property (strong, nonatomic) NSNumber *failedCode;
/**
* 默认的错误提示语
*/
@property (strong, nonatomic) NSString *defaultMessageValue;
/**
* 单例
*/
+ (instancetype)sharedConfig;
@end
NS_ASSUME_NONNULL_END
//
// SFResponseConfig.m
// template
//
// Created by shefeng on 2024/6/24.
//
#import "SFResponseConfig.h"
#define ResponseCodeDefaultKey @"code"
#define ResponseDataDefaultKey @"data"
#define ResponseMessageDefaultKey @"message"
#define ResponseCodeSuccessedDefaultValue @0
#define ResponseCodeFailedDefaultValue @500
#define ResponseMessageDefaultValue @"请求失败"
@implementation SFResponseConfig
+ (instancetype)sharedConfig{
static dispatch_once_t onceToken;
static SFResponseConfig *instance;
dispatch_once(&onceToken, ^{
instance = [[SFResponseConfig alloc] init];
});
return instance;
}
- (NSString *)codeKey{
if (_codeKey == nil || [@"" isEqualToString:_codeKey]) {
return ResponseCodeDefaultKey;
}
return _codeKey;
}
- (NSString *)dataKey{
if (_dataKey == nil || [@"" isEqualToString:_dataKey]) {
return ResponseDataDefaultKey;
}
return _dataKey;
}
- (NSString *)messageKey{
if (_messageKey == nil || [@"" isEqualToString:_messageKey]) {
return ResponseMessageDefaultKey;
}
return _messageKey;
}
- (NSNumber *)successedCode{
if (_successedCode == nil) {
return ResponseCodeSuccessedDefaultValue;
}
return _successedCode;
}
- (NSNumber *)failedCode{
if (_failedCode == nil) {
return ResponseCodeFailedDefaultValue;
}
return _failedCode;
}
- (NSString *)defaultMessageValue{
if (_defaultMessageValue == nil || [@"" isEqualToString:_defaultMessageValue]) {
return ResponseMessageDefaultValue;
}
return _defaultMessageValue;
}
@end
3.网络请求基类
//
// SFBaseRequest.h
// template
//
// Created by shefeng on 2024/6/20.
//
#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, SFContentType){
ApplicationJson,
ApplicationXWwwFormUrlencoded,
MultipartFormData
};
@interface SFBaseRequest : NSObject
+ (AFHTTPSessionManager *)sharedManager;
/**
* GET请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param completionBlock 完成的block
*/
+ (void)GET:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;
/**
* POST请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param completionBlock 完成的block
*/
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;
/**
* POST请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param contentType 请求Content-Type
* @param completionBlock 完成的block
*/
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers contentType:(SFContentType)contentType completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;
@end
NS_ASSUME_NONNULL_END
//
// SFBaseRequest.m
// template
//
// Created by shefeng on 2024/6/20.
//
#import "SFBaseRequest.h"
#import <MJExtension/MJExtension.h>
#import "SFRequestConfig.h"
#import "SFResponseConfig.h"
#define ResponseFailedDefaultValue @{[SFResponseConfig sharedConfig].codeKey:[SFResponseConfig sharedConfig].failedCode,[SFResponseConfig sharedConfig].messageKey:[SFResponseConfig sharedConfig].defaultMessageValue}
@implementation SFBaseRequest
+ (AFHTTPSessionManager *)sharedManager {
static AFHTTPSessionManager *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [AFHTTPSessionManager manager];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
// 客户端是否信任非法证书
securityPolicy.allowInvalidCertificates = [SFRequestConfig sharedConfig].allowInvalidCertificates;
// 是否在证书域字段中验证域名
securityPolicy.validatesDomainName = [SFRequestConfig sharedConfig].validatesDomainName;
instance.securityPolicy = securityPolicy;
instance.requestSerializer.timeoutInterval = [SFRequestConfig sharedConfig].timeoutInterval;
instance.responseSerializer.acceptableContentTypes = [SFRequestConfig sharedConfig].acceptableContentTypes;
});
return instance;
}
/**
* GET请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param completionBlock 完成的block
*/
+ (void)GET:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
[[SFBaseRequest sharedManager] GET:urlString parameters:params headers:headers progress:^(NSProgress * _Nonnull downloadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
}];
}
/**
* POST请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param completionBlock 完成的block
*/
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
[self POST:urlString params:params headers:headers contentType:ApplicationXWwwFormUrlencoded completionBlock:completionBlock];
}
/**
* POST请求
*
* @param urlString 请求url
* @param params 请求参数
* @param headers header参数
* @param contentType 请求Content-Type
* @param completionBlock 完成的block
*/
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers contentType:(SFContentType)contentType completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
if (contentType == ApplicationXWwwFormUrlencoded) {
[[self sharedManager].requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[[SFBaseRequest sharedManager] POST:urlString parameters:params headers:headers progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
}];
}else if (contentType == ApplicationJson) {
[[self sharedManager].requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:urlString parameters:params error:nil];
[request setValue:@"application/json"forHTTPHeaderField:@"Content-Type"];
if(headers != nil && headers.allKeys.count != 0){
for (NSString *key in headers.allKeys) {
NSString *value = [headers objectForKey:key];
[request addValue:value forHTTPHeaderField:key];
}
}
NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
[request setHTTPBody:body];
[[[SFBaseRequest sharedManager] dataTaskWithRequest:request uploadProgress:^(NSProgress * _Nonnull uploadProgress) {
} downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (!error) {
[self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
}else{
[self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
}
}] resume];
}else if (contentType == MultipartFormData) {
[[self sharedManager].requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
[[SFBaseRequest sharedManager] POST:urlString parameters:params headers:headers constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
NSArray *keyArray = [params allKeys];
for (NSString *key in keyArray) {
id value = params[key];
if ([value isKindOfClass:[NSString class]]) {
[formData appendPartWithFormData:[value dataUsingEncoding:NSUTF8StringEncoding] name:key];
}else if ([value isKindOfClass:[NSMutableArray class]]) {
[formData appendPartWithFormData:[NSKeyedArchiver archivedDataWithRootObject:value requiringSecureCoding:YES error:nil] name:key];
}else if ([value isKindOfClass:[NSArray class]]) {
[formData appendPartWithFormData:[NSKeyedArchiver archivedDataWithRootObject:value requiringSecureCoding:YES error:nil] name:key];
}
}
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
}];
}
}
/**
* 处理错误响应
*
* @param url 请求地址
* @param params 请求参数
* @param errMsg 错误信息
* @param completionBlock 完成的Block
*/
+ (void)handleError:(NSString *)url params:(NSDictionary *)params errMsg:(NSString *)errMsg completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
[self printLog:url params:params info:errMsg];
completionBlock([SFResponseConfig sharedConfig].failedCode.integerValue,nil,errMsg);
}
#pragma mark - private
/**
* 处理成功响应
*
* @param url 请求地址
* @param params 请求参数
* @param responseObject 响应数据
* @param completionBlock 完成的Block
*/
+ (void)handleSuccess:(NSString *)url params:(NSDictionary *)params responseObject:(id)responseObject completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
if(responseObject == nil){
[self handleError:url params:params errMsg:@"请求无响应" completionBlock:completionBlock];
}else {
if ([responseObject isKindOfClass:[NSDictionary class]]) {
NSDictionary *responseDict = (NSDictionary *)responseObject;
if ([responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].codeKey]
&& [responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].messageKey]
&& [responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].dataKey]) {
NSInteger code = [[responseDict objectForKey:[SFResponseConfig sharedConfig].codeKey] integerValue];
id data = [responseDict objectForKey:[SFResponseConfig sharedConfig].dataKey];
NSString *message = [responseDict objectForKey:[SFResponseConfig sharedConfig].messageKey];
[self printLog:url params:params info:[responseDict mj_JSONString]];
completionBlock(code,data,message);
}else{
[self handleError:url params:params errMsg:@"返回数据格式不正确" completionBlock:completionBlock];
}
}else{
[self handleError:url params:params errMsg:@"返回数据格式不正确" completionBlock:completionBlock];
}
}
}
/**
* 打印log
*
* @param url 请求地址
* @param params 请求参数
* @param info 响应信息
*/
+ (void)printLog:(NSString *)url params:(NSDictionary *)params info:(NSString *)info{
#ifdef DEBUG
NSString *urlInfo = [NSString stringWithFormat:@"请求地址:%@",url];
NSString *paramInfo = [NSString stringWithFormat:@"请求参数:%@",(params == nil ? @"" : [params mj_JSONString])];
NSString *responseInfo = [NSString stringWithFormat:@"请求响应:%@",info];
NSInteger maxLength = urlInfo.length;
if (paramInfo.length > maxLength) {
maxLength = paramInfo.length;
}
if (responseInfo.length > maxLength) {
maxLength = responseInfo.length;
}
NSLog(@"%@",[self buildLogString:maxLength info:nil]);
NSLog(@"%@",[self buildLogString:maxLength info:urlInfo]);
NSLog(@"%@",[self buildLogString:maxLength info:paramInfo]);
NSLog(@"%@",[self buildLogString:maxLength info:responseInfo]);
NSLog(@"%@",[self buildLogString:maxLength info:nil]);
#endif
}
/**
* 构建打印信息
*
* @param maxLength 最大长度
* @param info 信息
*
*/
+ (NSString *)buildLogString:(NSInteger)maxLength info:(NSString *)info{
//非第一行和最后一行的左侧*数量
NSInteger leftStarLength = 0;
//非第一行和最后一行的左侧*后的空格数量
NSInteger leftSpaceLength = 0;
//实际最大长度
maxLength += (leftStarLength + leftSpaceLength) * 2;
NSMutableString *mutableStr = [[NSMutableString alloc] init];
if(info == nil){
for (int i = 0; i < maxLength; i++) {
[mutableStr appendString:@"="];
}
}else{
for (int i = 0; i < leftStarLength; i++) {
[mutableStr appendString:@""];
}
for (int i = 0; i < leftSpaceLength; i++) {
[mutableStr appendString:@""];
}
[mutableStr appendString:info];
NSInteger rightSpaceLength = maxLength - leftStarLength - leftSpaceLength - info.length - leftStarLength;
for (int i = 0; i < rightSpaceLength; i++) {
[mutableStr appendString:@""];
}
for (int i = 0; i < leftStarLength; i++) {
[mutableStr appendString:@""];
}
}
return mutableStr;
}
@end
4.Java后台相关代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestObj {
private String name;
private String address;
}
package com.geenju.bcard.modules.app.controller;
import com.geenju.bcard.common.api.CommonResult;
import com.geenju.bcard.modules.app.dto.TestObj;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("/api/test")
public class TestController {
@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public CommonResult get(@RequestParam(value = "argsA") String argsA) {
log.info("get - argsA=" + argsA);
return CommonResult.success("");
}
@RequestMapping(value = "/postFormData", method = RequestMethod.POST)
@ResponseBody
public CommonResult postFormData(@RequestParam(value = "argsA") String argsA) {
log.info("postFormData - argsA=" + argsA);
return CommonResult.success("");
}
@RequestMapping(value = "/postXWwwFormUrlencoded", method = RequestMethod.POST)
@ResponseBody
public CommonResult postXWwwFormUrlencoded(@RequestParam(value = "argsA") String argsA) {
log.info("postXWwwFormUrlencoded - argsA=" + argsA);
return CommonResult.success("");
}
@RequestMapping(value = "/postJson", method = RequestMethod.POST)
@ResponseBody
public CommonResult postJson(@RequestBody TestObj testObj) {
log.info("postJson - testObj.name=" + testObj.getName() + " testObj.address=" + testObj.getAddress());
return CommonResult.success("");
}
}
5.使用
配置相关参数
[SFRequestConfig sharedConfig].timeoutInterval = 30;
[SFRequestConfig sharedConfig].allowInvalidCertificates = YES;
[SFRequestConfig sharedConfig].validatesDomainName = NO;
[SFRequestConfig sharedConfig].acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"image/jpeg",@"image/png",@"text/plain",@"application/json",nil];
[SFResponseConfig sharedConfig].codeKey = @"code";
[SFResponseConfig sharedConfig].dataKey = @"data";
[SFResponseConfig sharedConfig].messageKey = @"msg";
[SFResponseConfig sharedConfig].successedCode = @0;
[SFResponseConfig sharedConfig].failedCode = @500;
[SFResponseConfig sharedConfig].defaultMessageValue = @"请求失败";
调用
[self testGet:@"value of args"];
[self testPostFormData:@"value of args"];
[self testPostFormUrlencoded:@"value of args"];
[self testPostJson:@"hello" address:@"world"];
- (void)testGet:(NSString *)argsA{
[SFBaseRequest GET:@"http://192.168.0.121:9000/api/test/get" params:@{@"argsA":argsA} headers:@{} completionBlock:^(NSInteger code, id _Nonnull data, NSString * _Nonnull message) {
}];
}
- (void)testPostFormData:(NSString *)argsA{
[SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postFormData" params:@{@"argsA":argsA} headers:@{} completionBlock:^(NSInteger code, id _Nonnull data, NSString * _Nonnull message) {
}];
}
- (void)testPostFormUrlencoded:(NSString *)argsA{
[SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postXWwwFormUrlencoded" params:@{@"argsA":argsA} headers:@{} contentType:ApplicationXWwwFormUrlencoded completionBlock:^(NSInteger code, id _Nonnull data, NSString * _Nonnull message) {
}];
}
- (void)testPostJson:(NSString *)name address:(NSString *)address{
[SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postJson" params:@{@"name":name,@"address":address} headers:@{} contentType:ApplicationJson completionBlock:^(NSInteger code, id _Nonnull data, NSString * _Nonnull message) {
}];
}
6.调试
==============================================================
请求地址:http://192.168.0.121:9000/api/test/postXWwwFormUrlencoded
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
==============================================================
===========================================
请求地址:http://192.168.0.121:9000/api/test/get
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
===========================================
================================================
请求地址:http://192.168.0.121:9000/api/test/postJson
请求参数:{"name":"hello","address":"world"}
请求响应:{"msg":"操作成功","data":"","code":200}
================================================
====================================================
请求地址:http://192.168.0.121:9000/api/test/postFormData
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
====================================================