iOS URL安全的Base64編碼、解碼

參考
iOS開發(fā)探索-Base64編碼
iOS URL編碼&base64編碼
URL安全的Base64編碼,解碼

為什么需要對(duì)URL進(jìn)行編碼

網(wǎng)絡(luò)標(biāo)準(zhǔn)RFC 1738中規(guī)定URL中只能包含英文字、阿拉伯?dāng)?shù)字以及一些特殊字符。具體包括:字母和數(shù)組[0-9a-zA-Z]、特殊符號(hào)-._~:?#[]@!$&'()*+,;=` 。URL中若含有這些規(guī)定符號(hào)以外的符號(hào),URL都是不合法的,因此對(duì)于一些含有特殊符號(hào)或中文字符的URL,在請(qǐng)求前需要對(duì)URL進(jìn)行編碼。

常見的 URL編碼方式

下面URL作為本例中編碼演示的原始URL

NSString *urlString = @"http://lotheve.com/個(gè)人信息?name=URL編碼&other=這個(gè)參數(shù)有很多符號(hào)!*'();:@&=+ $,/?#[]%";

URL編碼 方式一

使用Foundation框架中的stringByAddingPercentEscapesUsingEncoding方法對(duì)url進(jìn)行編碼(該方法在iOS9后棄用)。編解碼代碼如下:

NSString *encodeUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //url編碼(utf8)
NSString *decodeUrlString = [encodeUrlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //url解碼
NSLog(@"編碼后的URL:%@",encodeUrlString);
NSLog(@"解碼后的URL:%@",decodeUrlString);

打印結(jié)果:

URL編碼方式一.png

使用這種方式編碼,從結(jié)果中可以看到除了中文被編碼,!*'();:@&=+ $,/?#[]% 這些符號(hào)中只有空格#[]%被編碼。事實(shí)上這種方式只能對(duì)以下14種字符編碼(不含冒號(hào)):`#%^{}[]|"<>空格這種方式適合于編碼路徑或者參數(shù)中包含中文或其他非法字符的URL,不適合于編碼參數(shù)中包含URL保留字符【如?/&=等】的URL,因?yàn)槿魠?shù)中含有例如&的保留字符,用這種方法不會(huì)對(duì)&進(jìn)行編碼,URL在識(shí)別的時(shí)候會(huì)將&作為參數(shù)的分隔符,最終識(shí)別的參數(shù)會(huì)有誤。不過(guò)可以先將需要轉(zhuǎn)碼的參數(shù)編碼之后再設(shè)置給URL,這樣就不會(huì)有問題了。

URL編碼 方式二

使用Foundation框架中的stringByAddingPercentEncodingWithAllowedCharacters方法對(duì)url進(jìn)行編碼(適用于iOS9之后)。通過(guò)傳入一個(gè)NSCharacterSet字符集對(duì)象決定對(duì)哪些字符進(jìn)行編碼,所有字符集對(duì)象中的字符都會(huì)被編碼。系統(tǒng)提供了一些包裝好的字符集對(duì)象,也可以自定義需要編碼的字符集對(duì)象。

NSString *encodeUrlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];  //編碼
NSString *decodeUrlString = [encodeUrlString stringByRemovingPercentEncoding];  //解碼
NSLog(@"編碼后的URL:%@",encodeUrlString);
NSLog(@"解碼后的URL:%@",decodeUrlString);

打印結(jié)果:

URL編碼方式二.png

各種系統(tǒng)包裝好的編碼字符集包含的字符范圍:

URLFragmentAllowedCharacterSet “#%<>[]^`{|}
URLHostAllowedCharacterSet “#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet “#%/:<>?@[]^`{|}
URLPathAllowedCharacterSet “#%;<>?[]^`{|}
URLQueryAllowedCharacterSet “#%<>[]^`{|}
URLUserAllowedCharacterSet “#%/:<>?@[]^`

URL編碼 方式三

使用CoreFoundation框架中的函數(shù)對(duì)url進(jìn)行編碼(該方法在iOS9之后同樣棄用)。

NSString *encodeUrlString = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)urlString, NULL, (CFStringRef)@"!*'();:@&=+ $,/?%#[]", kCFStringEncodingUTF8));  //編碼
NSString *decodeUrlString = CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)encodeUrlString, (CFStringRef)@"!*'();:@&=+ $,/?%#[]", kCFStringEncodingUTF8));  //解碼
NSLog(@"編碼后的URL:%@",encodeUrlString);
NSLog(@"解碼后的URL:%@",decodeUrlString);

打印結(jié)果:

URL編碼方式三.png

編碼函數(shù)中的第四個(gè)參數(shù)為需要編碼的字符的集合字符串,url中所有在這些字符范圍內(nèi)的字符都會(huì)被編碼,可以根據(jù)實(shí)際需求定要轉(zhuǎn)碼的字符范圍。

URL編碼一個(gè)容易混淆的地方

雖說(shuō)是URL編碼,但實(shí)際操作其實(shí)是對(duì)字符串進(jìn)行編碼,因此在編碼過(guò)程中編碼對(duì)象【字符串】并沒有什么“URL光環(huán)”,編碼時(shí)完全根據(jù)需要編碼的字符集合對(duì)整個(gè)URL進(jìn)行遍歷編碼,即便是對(duì)于協(xié)議名http,只要目標(biāo)編碼字符集合中含有“http”在,協(xié)議同樣也會(huì)被編碼。

Base64編、解碼

NSString *origStr = @"這是一個(gè)要經(jīng)過(guò)base64編碼的原始字符串";
NSData *data = [origStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodeString = [data base64EncodedStringWithOptions:0]; //編碼
NSData *decodeData = [[NSData alloc] initWithBase64EncodedString:base64EncodeString options:0]; //解碼
NSString *decodeString = [[NSString alloc] initWithData:decodeData encoding:NSUTF8StringEncoding];

NSLog(@"原始字符串:%@",origStr);
NSLog(@"base64編碼字符串:%@",base64EncodeString);
NSLog(@"base64解碼后字符串:%@",decodeString);

什么是 URL安全的Base64編碼

指的是將標(biāo)準(zhǔn)base64編碼后的字符串用url傳遞的場(chǎng)景,由于標(biāo)準(zhǔn)base64編碼結(jié)果中可能含有/+符號(hào),因此應(yīng)該先對(duì)base64編碼結(jié)果中的/+分別替換成-_,不然拼接到url中會(huì)有問題(/+在url作為保留字符有其自身的作用,如同&=?)。

如何進(jìn)行 URL安全的Base64編碼

Base64可以將二進(jìn)制轉(zhuǎn)碼成可見字符方便進(jìn)行http傳輸,但是base64轉(zhuǎn)碼時(shí)會(huì)生成“+”,“/”,“=”這些被URL進(jìn)行轉(zhuǎn)碼的特殊字符,導(dǎo)致兩方面數(shù)據(jù)不一致。
我們可以在發(fā)送前將“+”,“/”,“=”替換成URL不會(huì)轉(zhuǎn)碼的字符,接收到數(shù)據(jù)后,再將這些字符替換回去,再進(jìn)行解碼。

OC實(shí)現(xiàn):

#pragma - 將saveBase64編碼中的"-","_"字符串轉(zhuǎn)換成"+","/",字符串長(zhǎng)度余4倍的位補(bǔ)"="
+(NSData*)safeUrlBase64Decode:(NSString*)safeUrlbase64Str
{
    // '-' -> '+'
    // '_' -> '/'
    // 不足4倍長(zhǎng)度,補(bǔ)'='
    NSMutableString * base64Str = [[NSMutableString alloc]initWithString:safeUrlbase64Str];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
    base64Str = (NSMutableString * )[base64Str stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
    NSInteger mod4 = base64Str.length % 4;
    if(mod4 > 0)
        [base64Str appendString:[@"====" substringToIndex:(4-mod4)]];
    NSLog(@"Base64原文:%@", base64Str);
    return [GTMBase64 decodeData:[base64Str dataUsingEncoding:NSUTF8StringEncoding]];
    
}

#pragma - 因?yàn)锽ase64編碼中包含有+,/,=這些不安全的URL字符串,所以要進(jìn)行換字符
+(NSString*)safeUrlBase64Encode:(NSData*)data
{
    // '+' -> '-'
    // '/' -> '_'
    // '=' -> ''
    NSString * base64Str = [GTMBase64 stringByEncodingData:data];
    NSMutableString * safeBase64Str = [[NSMutableString alloc]initWithString:base64Str];
    safeBase64Str = (NSMutableString * )[safeBase64Str stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
    safeBase64Str = (NSMutableString * )[safeBase64Str stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
    safeBase64Str = (NSMutableString * )[safeBase64Str stringByReplacingOccurrencesOfString:@"=" withString:@""];
    NSLog(@"safeBase64編碼:%@", safeBase64Str);
    return safeBase64Str;
}

PHP、Java、Android

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容