前端学习之路


  • 首页

  • 归档

  • 分类

  • 标签

  • 搜索
close
小朱

小朱

前端学习之路

168 日志
37 分类
37 标签
RSS
GitHub
友情链接
  • 极客学院
  • caniuse
  • codepen
  • JS Bin
  • Babel在线编译
  • Iconfinder图标
  • 在线JSON格式化
  • 智能图像压缩

React-Native-目录结构

发表于 2017-05-22   |   分类于 React Native

项目目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
jxtrq_rn
├── /_test_ # RN生成,测试目录
├── /android # RN生成,android代码目录,具体见下图
├── /ios # RN生成,代码目录,具体见下图
├── /node_modules # 自动生成,安装依赖的目录,不会被提交
├── .babelrc # RN生成,Babel配置文件
├── .buckconfig # RN生成,Buck是Mac OS X和Linux使用的构建工具
├── .flowconfig # RN生成,Flow是一个静态的类型检查工具
├── .gitattributes # RN生成,配置Git对一个特定的子目录或子文件集运用那些设置项
├── .gitignore # RN生成,配置Git忽略提交的文件
├── .watchmanconfig # RN生成,Watchman用于监控文件变化,辅助实现工程修改所见即所得
├── yarn.lock # RN生成,Yarn是node包管理器,yarn.lock文件使程序在不同的机器上以同样的方式安装依赖
├── package.json # RN生成,用于描述项目的基本信息以及需要的依赖信息
├── index.android.js # RN生成,android入口文件
├── index.ios.js # RN生成,ios入口文件
|
├── index.web.js # 自定义,web入口文件
├── CHANGELOG.md # 自定义,版本更新日志
├── README.md # 自定义,项目运行说明
├── /docs # 自定义,项目相关的说明目录
| ├── /dev # 开发相关目录
| | ├── api # 接口相关目录
| ├── /work # 工作内容、计划目录
| └── /training # 培训相关文档
└── /app # 自定义,项目主体RN代码
├── config # 项目相关的配置信息,配置后台接口等
├── resources # 项目资源目录,目前主要是图片资源
├── actions # redux的action的目录
├── reducers # redux的reducer的目录,一般与actions对应
├── components # 组件目录,这些组件在项目中属于展示组件,不直接关联redux
├── containers # 组件目录,这些组件在项目中属于智能组件,直接关联redux,里面再返回展示组件
├── store # 初始化redux的目录
├── utils # 相当于工具类
├── styles # 项目公共样式、主题相关的目录
└── App.js # 平台无关的项目入口文件,通常根据条件决定显示欢迎页、登录页或主页

Ant Design Mobile 组件注意

发表于 2017-05-21   |   分类于 Ant Design

注意点

  • Popover、Progress外面如果没有View并且给高度的话可能不显示,外层是ScrollView应该也可以显示
  • Tabs最好指定activeKey否则可能有奇怪的返回第一个TabPane问题
  • SwipeAction放在TouchableHighlight外,否则会报 undefined is not an object (evaluation ‘this.refs.swipeoutContent.measure’) 错误

存在问题

  • PickerView 编辑不了,官方也没有给出RN上的demo
  • Range 使用不了,直接红屏报错Expected a component class,got [object Object]
  • Steps 不能水平方向
  • ListView中使用SwipeAction时效果不好,左右滑动会触发上下滑动,造成ListView滚动,不容易出现删除按钮,在部分Android机型上,目前已知的是“VT5000”上,点击时触发的是SwipeAction的onOpen方法,很少会触发ListView的onPress方法
  • Tabs.TabPane 在官网上写的tab属性支持 React.Element,目前经过确认是不支持的

Android-Small框架-基础

发表于 2017-05-06   |   分类于 Android

Small github地址
Small官方教程
使用Small进行Android模块化开发
small的插件化的基本使用

简介

插件模块是Small特有的插件化与IDE完美结合的产物,做到了“模块即组件,组件即插件”。 组件是工程的角度,插件是应用的角度。只有做到了清晰的组件解耦,才能更好的拆分插件模块。

出于业务需求考虑,Small定义了两类插件:公共库插件与应用插件。应用插件相对简单,就是用来把大应用拆分成一个个小的业务单元,公共库插件则是为这些业务单元提供公共的代码与资源。

通过设定 URI,宿主、本地化应用插件、本地化web插件、在线网页,以及任何自定义的插件之间能够相互调起与传递参数。

目前已支持 Android 、iOS 以及 HTML5 插件。并且三者之间可以通过同一套 JavaScript 接口进行通信。

开发基础

  • 通过 build.gradle 集成 Small,项目的build.gradle文件中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    buildscript {
    repositories {
    jcenter()
    }
    dependencies {
    ...
    classpath 'net.wequick.tools.build:gradle-small:1.2.0-beta3'
    }
    }
    ...
    apply plugin: 'net.wequick.small'
    small {
    aarVersion = '1.2.0-beta3'
    }
  • 通过 自定义Application 初始化 Small,app > java > com.example.mysmall > SmallApp中

    1
    2
    3
    4
    5
    6
    public class SmallApp extends Application {
    public SmallApp() {
    // Small框架初始化
    Small.preSetUp(this);
    }
    }

    AndroidManifest.xml中

    1
    2
    3
    4
    <application
    android:name=".SmallApp"
    ...>
    </application>
  • 创建插件模块 App.main,注意包名为com.example.app.main

  • 通过 buildLib,buildBundle 编译 Small 插件,命令后面可添加 -Dbundle.arch=x86

    1
    2
    gradlew buildLib -q
    gradlew buildBundle -q
  • 通过 bundle.json 配置插件路由,右键 app 模块,New > Folder > Assets Folder 新建 assets 目录,在新建配置文件bundle.json内容如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    "version": "1.0.0",
    "bundles": [
    {
    "uri": "main",
    "pkg": "com.example.appmain"
    }
    ]
    }
  • 通过 Small.openUri 启动插件,宿主的 app > java > com.example.mysmall > MainActivity中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Override
    protected void onStart() {
    super.onStart();
    // Small插件初始化
    Small.setUp(this, new Small.OnCompleteListener() {
    @Override
    public void onComplete() {
    // 通过uri启动插件
    Small.openUri("main", MainActivity.this);
    }
    });
    }
  • 创建公共库插件模块 Lib.style,注意包名为com.example.lib.style,将app.main/src/main/res/values 下除了strings.xml的文件移动到lib.style/src/main/res/values 目录下,修改 lib.style/src/main/res/colors.xml中colorPrimary值为#2FA739

  • 添加公共库引用,修改 app.main/build.gradle,增加对 lib.style 的依赖

    1
    2
    3
    4
    dependencies {
    ...
    compile project(':lib.style')
    }
  • 添加插件路由

    1
    2
    3
    4
    5
    6
    "bundles": [
    ...
    {
    "pkg": "com.example.libstyle"
    }
    ]
  • 重新运行

    1
    2
    3
    gradlew cleanLib -q
    gradlew buildLib -q
    gradlew buildBundle -q

工程结构图

  • 宿主:工程中的app模块,不能依赖lib.xxx

    • assets目录下的bundle.json声明宿主使用的插件,每个bundle可定义一些rule去启动特定的Activity
    • 可增加签名配置和共享的依赖库
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      signingConfigs {
      release {
      storeFile file('../sign/release.jks')
      storePassword "5mall@ndro!d"
      keyAlias "small"
      keyPassword "5mall@ndro!d"
      }
      }
      buildTypes {
      release {
      signingConfig signingConfigs.release
      }
      }
      [...]
      compile 'com.android.support:design:23.1.1'
  • 公共库插件:工程中的lib.xxx模块,是标准的Android库工程

    • 第三方依赖合并到lib.vendor中管理
    • 样式相关的资源放在lib.style中管理
    • 其它工具类,以及网络、存储等跨业务模块的底层代码可以在lib.utils中管理
    • 可以通过compile project(‘:插件模块名’)来被应用插件模块所引用
    • 编译时(buildLib)会被打包成为一个可独立更新的插件
  • 业务插件:工程中的app.xxx模块,是标准的Android应用工程
    • app.main一般是程序的入口,并控制业务逻辑的主线
    • 其他app.xxx一般是业务逻辑的支线,插件内的业务逻辑之间关联性较强
    • app.xxx可以依赖多个lib.xxx
    • 可独立运行、独立更新
  • 宿主分身模块:工程中的app+xxx模块,是标准的Android应用工程
    • 分身是宿主的一部分,最终编译到宿主中,不可被独立更新
    • 具备占坑(stub)的功能,即在宿主中预留特定的(无法插件化的)资源、代码或manifest项目,使系统可以正常识别,任何稳定的资源、代码、第三方库也可使用分身下沉到宿主中,以减少插件体积
    • 它提供了可以让插件模块自由访问其中的资源与代码的能力,并为所有插件模块添加该依赖
    • 需要占坑的项目为
      • 必须在宿主Manifest注册的项目,包括:所有权限,受限 Activity,任何 Provider、Service、BroadcastReceiver
      • 必须在宿主占坑的资源,包括:转场动画、通知栏图标、自定义视图、桌面快捷方式图标
  • web插件工程:工程中的web.xxx模块,本地网页组件

常用命令

  • gradlew samll # 查看编译情况
  • gradlew buildLib -q # 编译公共库插件,不仅编译了lib.xxx,还编译了宿主模块
  • gradlew buildBundle -q # 编译业务插件
  • gradlew -p app.main assembleRelease # 单独编译一个插件app.main
  • gradlew cleanLib -q # 清除公共库
  • gradlew cleanBundle -q # 清除业务库

其中-q是安静模式,可以让输出更好看,也可以不加。对插件的编译,会在app/smallLibs/生成对应的so文件,这些so文件本质上就是独立的apk包。

常用API

// 框架初始化
Small.preSetUp(this);

// 浏览器跳转url
Small.setBaseUri(“http://code.wequick.net/small-sample/“);

// 在宿主的 Application 里指定是否从 assets 读取插件,有build.gradle 中 buildToAssets的值指定
Small.setLoadFromAssets(BuildConfig.LOAD_FROM_ASSETS);

// 设定基本的跳转地址
Small.openUri(“https://github.com/wequick/Small/issues“, MainActivity.this);

// 更新bundles.json和version信息
Small.updateManifest(info.manifest, false)

// 获取补丁文件目录
net.wequick.small.Bundle bundle = Small.getBundle(u.packageName);
File file = bundle.getPatchFile();

// 使更新后的插件生效
bundle.upgrade();

// 暗度插件意图
Small.wrapIntent(intent);

// 创建远程fragment
Small.createObject(“fragment-v4”, sUris[position], MainActivity.this);

// 设置网页的基本回调
Small.setWebViewClient(new MyWebViewClient());

// TODO
Small.getBundleVersions()

// TODO
Small.setWebActivityTheme(R.style.AppTheme);

// TODO
Small.getIsNewHostApp()

其它

  • 对插件的编译,会在app/smallLibs/生成对应的so文件,这些so文件本质上就是独立的apk包,所以修改某个模块之后,要在运行时生效,必须先编译对应的插件,更新smallLibs下的.so文件
  • 编译后的lib,如果删除资源再编译就会出现错误“No support deleting resources on lib.* now!”,所以在删除lib中的资源后,需要删除lib.xxx模块下的public.txt再通过cleanLib, buildLib, cleanBundle, buildBundle重新编译
  • 从插件初始化,到初始化完成会耗费几百毫秒,甚至更多可以考虑将欢迎页放入宿主工程之中,如果欢迎页有比较复杂的广告逻辑或统计相关的逻辑,则可以考虑在主插件中做一个透明的Activity来处理
  • 关于插件的Manifest,可以在插件的Manifest中指定application,每个插件的Application都会在Small.setup时被创建;对于需要处理android:configChanges的Activity需要在宿主中注册;如果要通过uri启动Activity,则对应Activity应该Manifest中进行注册,如果需app插件可以独立运行,但在Manifest中至少要注册一个主Activity

热更新?

打开项目的app工程也就是入口工程,文件夹里有一个smallLibs文件夹,里面有一个armeabi文件,里面是.so文件,这些文件就是通过buildLib和buildBundle来把非宿主的app中的文件打包成的.so文件。最终安装到手机上的apk其实就是只有宿主的apk和其内部的.so文件,通过加载.so文件来实现加载插件中的文件。热更新就是更新bundle.json文件和插件.so文件的过程。

增量更新?

增量更新的原理是:在服务器端先拿新版本安装包和旧版本安装包进行对比,在生成差异包之后下发,之后客户端根据对应的差异包和本地旧版本安装包合成,便生成了新版本安装包。

对于Small框架,它把每个插件都编译成.so文件,然后存放到app的native目录下,不过,如果它发现自己的download目录有新的插件,那么就会去加载download目录下的插件,并且这种加载优先权是最大的,也就是说它会优先加载download目录下的插件。所以,如果我们要做增量更新,旧文件就从app的native目录进行读取,然后从服务器端下载增量包,最后合成的文件存放到download目录下,这样每次插件启动都会到download目录下加载新的插件。

React-Native-嵌入到android

发表于 2017-05-04   |   分类于 React Native

参考

嵌入到现有原生应用
史上最详细的Android原生APP中添加ReactNative 进行混合开发教程

配置步骤

创建android项目

  • 打开Android studio,Start a new Android Studio project 新建项目
  • 其中 Application name: ReactNativeAppDemo,Company Domain: example.com,Minimum SDK: API 16:Android 4.1(Jelly Bean)
  • 添加Empty Activity,其中 Activity Name: MainActivity,Layout Name: activity_main
  • 在Android视图下,右键com.example.reactnativeappdemo,New -> Java Class,其中 Name:MyReactActivity

MainActivity.java完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.example.reactnativeappdemo;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.reactive_button);
btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.reactive_button:
Intent intent = new Intent(MainActivity.this,MyReactActivity.class);
startActivity(intent);
break;
default:
break;
}
}
}

MyReactActivity完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.example.reactnativeappdemo;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage;
public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler{
private ReactRootView mReactRootView;
private ReactInstanceManager mReactInstanceManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
// 注意这里的HelloWorld必须对应“index.android.js”中的
// “AppRegistry.registerComponent()”的第一个参数
mReactRootView.startReactApplication(mReactInstanceManager, "HelloWorld", null);
setContentView(mReactRootView);
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostPause(this);
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostResume(this, this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mReactInstanceManager != null) {
mReactInstanceManager.onHostDestroy();
}
}
@Override
public void onBackPressed() {
if (mReactInstanceManager != null) {
mReactInstanceManager.onBackPressed();
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) {
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
}
}

React Native集成到android项目中

  • cmd进入在ReactNativeAPPDemo的根目录,执行 npm init
  • 执行 npm install –save react react-native
  • 执行 curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig,作用是下载.flowconfig配置文件,用于约束js代码的写法,也可以手动创建文件在浏览器打开这个网址复制内容,这一步非必需
  • package.json文件如下,注意react和react native的版本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {
    "name": "reactnativeappdemo",
    "version": "1.0.0",
    "description": "",
    "main": "index.android.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node node_modules/react-native/local-cli/cli.js start"
    },
    "author": "",
    "license": "ISC",
    "dependencies": {
    "react": "~15.4.1",
    "react-native": "0.42.0"
    }
    }
  • 添加index.android.js文件到项目中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import React from 'react';
    import {
    AppRegistry,
    StyleSheet,
    Text,
    View
    } from 'react-native';
    class HelloWorld extends React.Component {
    render() {
    return (
    <View style={styles.container}>
    <Text style={styles.hello}>React Native:Hello, World</Text>
    </View>
    );
    }
    }
    var styles = StyleSheet.create({
    container: {
    flex: 1,
    justifyContent: 'center',
    },
    hello: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    },
    });
    AppRegistry.registerComponent('HelloWorld', () => HelloWorld);
  • app/build.gradle配置

    1
    2
    3
    4
    dependencies {
    ...
    compile "com.facebook.react:react-native:+" // From node_modules.
    }
  • 整个工程build.gradle配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    allprojects {
    repositories {
    ...
    maven {
    // All of React Native (JS, Android binaries) is installed from npm
    url "$rootDir/node_modules/react-native/android"
    }
    }
    ...
    }
  • app/src/main/AndroidManifest.xml配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ...
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <application
    ...
    <activity
    android:name=".MyReactActivity"
    android:label="@string/app_name"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar">
    </activity>
    <activity
    android:name="com.facebook.react.devsupport.DevSettingsActivity">
    </activity>
    </application>

启动项目

  • 先运行android项目
  • cmd进入在ReactNativeAPPDemo的根目录,执行 npm start

可能出现的错误

如果点击按钮后应用崩溃了,同时Android Studio中报错 permission denied for this window type ,需要开启悬浮窗(overlay)权限。
解决方法一,修改MainActivity.java中代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.reactive_button:
// 修改了这里的代码
if (Build.VERSION.SDK_INT >= 23) {
if(!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(intent);
return;
} else {
//绘ui代码, 这里说明6.0系统已经有权限了
Intent intent = new Intent(MainActivity.this,MyReactActivity.class);
startActivity(intent);
}
} else {
//绘ui代码,这里android6.0以下的系统直接绘出即可
Intent intent = new Intent(MainActivity.this,MyReactActivity.class);
startActivity(intent);
}
break;
default:
break;
}
}

解决方法二,修改MyReactActivity.java中代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MyReactActivity extends AppCompatActivity implements DefaultHardwareBackBtnHandler{
private static final int OVERLAY_PERMISSION_REQ_CODE =10005 ;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
}
}
...
}
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
// SYSTEM_ALERT_WINDOW permission not granted...
}
}
}
}
}

React-Native-android-apk

发表于 2017-05-03   |   分类于 React Native

RN项目打包

  • cmd下执行 cd .android 进入系统android目录
  • 执行 keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000 ,它会在android目录(C:/Users/Administrator/.android/)下生成一个叫做my-release-key.keystore的密钥库文件
  • 把my-release-key.keystore文件放到工程中的android/app文件夹下
  • 编辑~/.gradle/gradle.properties,~表示用户目录,比如windows上可能是C:\Users\用户名,而mac上可能是/Users/用户名,没有就创建一个,添加如下的代码,把其中的**替换为相应密码:

    1
    2
    3
    4
    MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
    MYAPP_RELEASE_KEY_ALIAS=my-key-alias
    MYAPP_RELEASE_STORE_PASSWORD=*****
    MYAPP_RELEASE_KEY_PASSWORD=*****
  • 编辑你项目目录下的android/app/build.gradle,添加如下的签名配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ...
    android {
    ...
    defaultConfig { ... }
    signingConfigs {
    release {
    storeFile file(MYAPP_RELEASE_STORE_FILE)
    storePassword MYAPP_RELEASE_STORE_PASSWORD
    keyAlias MYAPP_RELEASE_KEY_ALIAS
    keyPassword MYAPP_RELEASE_KEY_PASSWORD
    }
    }
    buildTypes {
    release {
    ...
    signingConfig signingConfigs.release
    }
    }
    }
    ...
  • cmd进入项目android目录,执行 gradlew installRelease,生成的APK文件位于项目的android/app/build/outputs/apk/app-release.apk

报错处理

执行gradlew installRelease 如果报错Unable to process incoming event 'ProcessComplete' <ProgressCompleteEvent>,这种错误
需要在在混淆文件/android/app/proguard-rules.pro末尾中加入

1
2
-keep class android.text {* ;}
-dontwarn android.text.*

修改安装文件图标及显示名称

将 /android/app/src/main/res/values/strings.xml 中 app_name 的值改成想要的app名称

将 /android/app/src/main/res/ 路径下,mipmap-开头的目录中的图片替换为同名的其它图片

TCP-基础

发表于 2017-05-02   |   分类于 TCP

三次握手

  • 第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认。
  • 第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态。
  • 第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

    第一个包,即Client发给Server的SYN中途被丢,Client会周期性超时重传,直到收到Server的确认;
    第二个包,即Server发给Client的SYN+ACK中途被丢,Server会周期性超时重传,直到收到Client的确认;
    第三个包,即Client发给Server的ACK中途被丢:
      a)假定此时双方都没有数据发送,Server会周期性超时重传SYN+ACK,直到收到Client的确认收到之后Server的TCP连接业也为established状态;
      b)假定此时Client有数据发送,Server收到Client的Data+ACK,自然会切换为established状态,并接受Client的Data;
      c)假定Server有数据发送,数据发送不了,会一直周期性超时重传SYN+ACK,直到收到Client的确认才可以发送数据。

为什么连接的时候需要三次握手?

在谢希仁的《计算机网络》中是这样说的:“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。”书中举例:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

网上查到:“这个问题的本质是,信道不可靠,但是通信双发需要就某个问题达成一致,而要解决这个问题,无论你在消息中包含什么信息,三次通信是理论上的最小值。所以三次握手不是TCP本身的要求,而是为了满足”在不可靠信道上可靠地传输信息”这一需求所导致的。这可视为对“三次握手”目的的另一种解答思路。

四次挥手

  • 第一次挥手:主机1(可以使客户端,也可以是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了。
  • 第二次挥手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求。
  • 第三次挥手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态。
  • 第四次挥手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。

为什么断开的时候需要四次挥手?

因为TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

表单-设计

发表于 2017-04-30   |   分类于 UI

别人评论《Web表单设计:点石成金的艺术》这本书非常好,ANT DESING 官网的资源中也提到了这本书,于是买了一本看看。这本书已经绝版了,我买的是影印版的,图片大多数都看不清,我个人对这本书并没有什么特别好的感觉,没感觉到对自己有什么帮助。现在把每章的最佳实践记录下来,希望能够加深些理解,后期需要时能够想到这本书。

设计原则

  • 尽量减少痛苦 人们要的是填完表单之后的东西,所以填写过程应尽量简洁、容易。
  • 说明填写完成路径 几乎每个表单的目标就是填完,表单应清晰告诉人们如何完成这一目标。
  • 考虑情景 表单并非凭空存在。它们几乎都是更广泛情境(受众群众、应用、业务)的组成部分,这些情境决定了如何使用表单。
  • 确保一致沟通 表单是顾客和公司之间对话的中间人。多个团队参与对话(市场营销、隐私部门、工程部、设计部、商业部等),但表单只能用一种声音说话。

表单的组织

  • 应当花时间评估表单中的问题。应当提高警觉,去除一切不必要的问题。
  • 表单所提问题(标签)应当尽量简洁。
  • 如果人们会误解简洁标签,应当寻找使用自然语言的机会,澄清表单要求人们回答的问题。
  • 表单所提问题来自多个不同人或部门,应当确保表单统一口径。
  • 可以将表单内容组织成逻辑组,有助于浏览和完成填写。
  • 如果可能,应当以对话形式构建表单。主题间的自然间断有助于组织表单。
  • 如果表单可自然分成若干主题,一个网页可能就足够组织表单。
  • 如果表单包含大量问题,同时有若干主题,可能需要多个网页来组织表单。
  • 如果表单包含大量问题,而只和一个主题相关,可能需要多个网页来组织表单。
  • 可以考虑在表单填完之后提出可选问题。可能会比在初始表单中就提出这些问题能获得更多答案。
  • 可以考虑采用Web惯例调查发现特定类型网站如何组织表单。
  • 应当采用最少的必要视觉信息来区分内容组。
  • 首字母应当大写,使内容组更容易浏览。

完成之路

  • 确保表单名称符合人们的期望,并简洁解释每个表单的用途。
  • 如果表单需要时间或者查询信息才能填写那么可以采用起始页来设定人们的期望。
  • 由始至终采用清晰浏览线和有效视觉步伐来引导人们,确保说明清晰的填写完成路径。
  • 对于关键任务表单,比如结算表单或者注册表单,应当去除会分散注意力的部分、任何导致人们放弃填写的连接或内容。
  • 如果表单分为多个已知的有序网页,可以采用进程指示来传达范围、状态和位置等信息。
  • 如果表单没有清晰的有序网页,不要采用进程指示,应当采用更笼统的进程指示,而不要设置错误期望。
  • 设计表单布局时,应考虑使用Tab键的“跳转”体验。
  • 采用“tabindex”HTML属性来控制表单的跳转顺序。

标签

  • 表单标签应当使用简洁的自然语言,大小写一致,所提问题应当尽量直观,容易理解。
  • 如果要减少填写时间,或者出于本地化原因,标签长度需要灵活多变,可采用顶对齐标签。
  • 如果与上述目标类似,但垂直屏幕空间有限,可采用右对齐标签。
  • 如要求人们浏览表单标签,知道必填问题或者回答多个问题中的若干特定问题,可采用左对齐标签。
  • 如果表单非常短,屏幕空间极度有限,可采用输入框内标签,同时应当确保合适的交互和情境。
  • 确保清晰区分标签和数据,特别是对于输入框内标签。
  • 如果考虑在同一应用工具的不同表单采用不同标签对齐方式,应当平衡情境和一致性。
  • 单一表格中采用不同标签对齐方式会破坏明确完成路径,人们会觉得迷惑。

输入框

  • 应当为所提问题提供合适的输入框:属于是否问题?还是需要从多个互斥选项中选择一项?等等。
  • 如有可能,应当确保输入框长度能提供有意义的暗示,以帮助人们有效回答问题。
  • 如果不是上述情况,输入框长度应当保持一致,为答案提供足够空间。
  • 尽量避免出现可选输入框。
  • 如果表单大部分输入是必填项,标明可选项即可。
  • 如果表单中大部分是可选项,表名必填项即可。
  • 标明表单必填或可选项,文字是最清晰的办法。但“*”代表必填项相对容易理解。
  • 将必填项或者可选项标识器与输入标签相关联,便于人们知道需要回答哪些问题。
  • 如果输入框存在自然结构,能为人们回答问题提供有价值线索,应当通过视觉方式将输入框进行分组,并清晰传达自然结构。
  • 如果答案明显有多种格式,应当考虑使用弹性输入框。
  • 确保弹性输入框不会导致填写简单问题变得复杂。

动作

  • 尽量避免表单中出现次动作,当向人们提供完成表单的单一路径。
  • 如果需要使用次动作,应当确保主动作和次动作视觉差异清晰。
  • 如果表单所提问题分布在多个网页,主动作应当让人们更接近完成表单,而次动作应当允许人们返回。
  • 主动作与输入框对齐,能提供明确路径完成表单。
  • 如果的确需要采用具有潜在破坏性的次动作,比如重置或者清除,应当提供简便的撤销方法。
  • 处理表单时,应当明确表达,避免重复提交。
  • 不要依赖帮助文字来提醒人们不要两次点击主动作,而应当通过禁用主动作按钮来阻止人们这样做。
  • 思考组合服务条款和主动作的机会,以确保法律要求合理化。

帮助文字

  • 不要依赖帮助文字来弥补表单缺点,尽量减少表单中的帮助文字,以促成更好的设计方案。
  • 帮助文字最合适解释人们不熟悉的数据,例如,为什么要问这些问题、安全和隐私、建议回答问题的方式及说明可填项。
  • 简洁的帮助文字毗邻问题是最清晰的方式。
  • 输入框内的帮助文字只能用于提供回答问题的方式。
  • 如果人们知道表单问题答案,但不确定如何回答或者为什么回答,可以考虑使用自动即时帮助系统。
  • 如果表单问题人们不熟悉或者复杂,而且可能同样的人会多次使用,可以考虑采用用户激活的帮助系统。
  • 除非每个问题都需要很多帮助文字或者内容(图像、图表),使用即时系统可以避免网页跳动拉伸。
  • 如果帮助内容很多,可以使用一致的帮助区域,不要使用即时帮助。
  • 帮助文字应当尽可能具体。如果帮助文字适用于一组相关输入框,而不是一个输入框,考虑采用网页一部分显示帮助内容,清晰表明输入框组和帮助文字之间的关系。
  • 图标、链接或按钮用于用户激活的帮助文字触发器,应放在标签旁,不要放在输入框旁。
  • 如果要求用户填入敏感资料,考虑使用有操作含义的帮助文字,允许人们确认资料安全。

错误与成功

  • 如果有错误阻碍人们完成填写表单,应该明确告诉人们。错误消息可以说是表单中最重要元素。确保以最重要的形式表现错误。
  • 应当在情境中显示错误消息,以便快速解决。
  • 应当提供可操作的补救措施,帮助人们能够轻松解决错误。
  • 顶部错误消息应当用来说明有错误发生以及相应的解决方案。如果发生多个错误,应当都罗列在顶部消息中。
  • 如果有输入框发生错误,应当采用双重视觉强调清晰标示,确保人们能看到。
  • 从视觉上将表单出错元素与顶部错误消息联系起来,清晰传达需要解决错误才能继续。
  • 红色文字和警告图标应当用于错误消息。
  • 短表单可不采用顶部错误消息或者指示标明发生错误的输入框。如果要采用这种方式,一定要谨慎。
  • 如果表单填写成功,应当用成功消息清晰传达并通过成功消息显示结果。
  • 根据情境提供成功消息,不要阻止进程。
  • 考虑采用动态成功消息突出表单提交成功的结果。
  • 避免成功消息页面成为死胡同。

即时验证

  • 考虑使用即时验证,以确认或者建议有效答案,并帮助人们在限制范围内输入。
  • 即时确认最适合用于错误率高、或者有特定格式要求的问题。
  • 即时建议最适合用于大量可供选择有效答案的情况。
  • 即时质量指示条能引导人们更好地回答复杂问题。
  • 如果需要即时验证答案,应当在人们输完答案之后进行,不要在输入过程中进行。
  • 如果需要将答复转成特定格式,应当确保在人们提供答案后转换,不要在填写过程中转换。
  • 如果有输入限制,应当采用实时、动态更新的方法传递输入限制。

多余输入

  • 仔细检查表单所有问题,千方百计去除多余的问题。
  • 寻找人们回答问题的模式,准确推断答案。
  • 注意,不要为了去除问题而使问题复杂化。
  • 通过恰当设置满足多数人需要的默认选择,智能默认可以帮助人们回答问题。
  • 人们会忽视默认选项,所以要确保默认选项符合多数人目标。
  • 只要有可能,单选按钮都应当设置默认选项。如果没有明确的默认选项,人们仍可能会明白需要做出选择。但如果他们不明白,就会发生错误。
  • 设置个性化默认选择,客户能更快完成表单,因为答案具有“粘性”。
  • 考虑个性化默认选择发挥作用的地方。并不是表单每项输入都能设为个性化默认选项。

额外输入

  • 额外输入可以提供更多选项或者高级选项,满足有需要的用户,同时不妨碍不需要的用户。
  • 应当根据客户需求的优先顺序,安排额外输入。主要用例应当总是直接而且可见;次要用例应当点击一次鼠标即可见。
  • 如果允许人们激活额外输入,额外输入会比自动浮现更受欢迎。
  • 确保触发额外选项的操作措辞明确。如果额外选项自动触发,应当提供线索(图标和文字)来预设期望。
  • 对于单一表单,应当保持一致的额外输入方式。
  • 如果需要显示大量额外输入,可以考虑采用层叠方式代替即时显示方式,避免网页跳动以及用户迷失方向。
  • 确保叠层不会遮住帮助人们填写的输入框,确保人们仍然可以自行填写。
  • 如果额外选项需要单独考虑,应当使用模式叠层。
  • 确保提供用户明确办法关闭或者取消模式叠层并返回表单。
  • 返回表单时,应当显示在叠层中所选选项。
  • 如果吸引客户是主要目标,额外输入可以采用通过选择来引导人们的迷人方试。

基于选择的输入

  • 如果每个初始选项的额外输入选项数量很多,那么网页级别的基于选择的输入选项可能是最佳方案。虽然需要两个网页来拆分表单,但动态隐藏和显示额外输入选项不会让人们产生困惑,人们也无需怀疑选项之间是否互斥。
  • 在综合可用性、满意度和眼动跟踪指标方面,垂直选项卡和水平选项卡的表现都不错,但存在选择互斥问题。关于两种方案哪个能更好解决互斥问题,我手上的数据截然相反,因此两种方案似乎都有问题。如果能通过巧妙的交互设计或者视觉设计避开互斥问题,这两个方案就会表现良好。
  • 如果初始选项列表较长(4或者5个以上),而且每个选项都自带一套基于选择的输入,最好能针对额外选项采用下拉列表和视觉分组。
  • 如果每个初始项只有几个额外的输入选项,单选按钮下方显示或者单选按钮内显示是最佳方案。我见过两种方法由于过多页面跳动造成混乱,额外输入项与初始选择之间的关联丧失,因此要谨慎使用。但如果每个选择只有1到3个额外输入项,我会使用单选按钮即时显示。如果可能,应当确定使用清晰的视觉联系和过渡。
  • 所有非活动选项显示或者全部选项都显示基本不能接受,因为选项太多,人们马上会被打昏,而且其中太多选项与人们的目标无关。
  • 整体而言,隐藏无关的表单控件能减轻表单对眼睛的压力,人们能迅速完成表单,除非人们需要。
  • 整体而言,将初始选项及其基于选项的输入靠近显示,能达到最高的满意度。
  • 任何情况下,应当保持初始选项之间的联系清晰。不要让人们看不到顶级初始选项。
  • 任何情况下,清晰显示基于选择的输入项和触发控件之间的关系。
  • 任何情况下,应避免页面过多跳动,页面跳动会中断基于选择的输入项和初始选项之间的关联。

循序渐进

  • 规划客户对Web服务的最初体验时,可以考虑采用循序渐进的方式以避免出现注册表单。
  • 如果要采用循序渐进方案,应当确保潜在客户能明白如何使用以及为什么要使用你提供的服务。
  • 如果要为潜在客户自动生成账户,应当确保客户有清晰访问账户的方式。人们可能会忽视或者不看账户生成的提醒邮件,还可能不确定他们是否已经拥有账户。
  • 如果只是将注册表单的输入框分布到多个页面,则不要使用循序渐进方案。因为这可能会降低效率,也使人们感到不快。

React-依赖

发表于 2017-04-28   |   分类于 React

create-react-app 初始化空的react项目

redux-saga 处理异步利器

redux-sequence-action 按序发起action

React-Native-打开文件

发表于 2017-04-07   |   分类于 React Native

本地应用打开文件 react-native-file-opener

  • NPM install

    1
    npm install --save react-native-file-opener
  • IOS install

    1
    2
    在Xcode中,将node_modules/react-native-file-opener/ios/RNFileOpener.xcodeproj添加到项目的Libraries目录;
    将Libraries/RNFileOpener.xcodeproj/Products/libRNFileOpener.a拖拽到Build Phases -> Link Binary With Libraries中。
  • Android install

    1
    2
    3
    4
    // file: android/settings.gradle
    ...
    include ':react-native-file-opener'
    project(':react-native-file-opener').projectDir = new File(settingsDir, '../node_modules/react-native-file-opener/android')
    1
    2
    3
    4
    5
    6
    // file: android/app/build.gradle
    ...
    dependencies {
    ...
    compile project(':react-native-file-opener')
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // file: MainActivity.java
    ...
    import com.fileopener.FileOpenerPackage;//<- import package
    public class MainActivity extends ReactActivity {
    @Override
    protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
    new MainReactPackage(),
    new FileOpenerPackage() //<- Add package
    );
    }
    ...
    }
  • Usage
    在上一篇React-Native-上传下载例子的基础上,添加如下代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ...
    import FileOpener from 'react-native-file-opener';
    ...
    class TestFileStream extends Component {
    ...
    openFile(fileName) {
    const FilePath = Platform.OS === 'android' ? dirs.DCIMDir + '/' + fileName : dirs.DocumentDir + '/' + fileName;
    const FileMimeType = 'image/jpg';
    FileOpener.open(
    FilePath,
    FileMimeType
    ).then((msg) => {
    console.log('success!!')
    },(err) => {
    console.log('打开失败:', err)
    });
    }
    ...
    }
    export default TestFileStream;

Http-基础

发表于 2017-04-03   |   分类于 Http

简介

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW)服务器传输超文本到本地浏览器的传送协议。它基于TCP/IP通信协议来传递数据,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。HTTP协议是无状态协议,无状态是指协议对于事务处理没有记忆能力,如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间。HTTP协议永远都是客户端发起请求,服务器回送响应。这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。

工作流程

一次HTTP操作称为一个事务,其工作过程可分为四步:

  • 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
  • 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
  • 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
  • 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。

如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。

请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

  • GET – 请求指定的页面信息,并返回实体主体。
  • HEAD – 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
  • POST – 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
  • PUT – 从客户端向服务器传送的数据取代指定的文档的内容。
  • DELETE – 请求服务器删除指定的页面。
  • CONNECT – HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
  • OPTIONS – 允许客户端查看服务器的性能。
  • TRACE – 回显服务器收到的请求,主要用于测试或诊断。

状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

  • 1xx:指示信息–表示请求已接收,继续处理
  • 2xx:成功–表示请求已被成功接收、理解、接受
  • 3xx:重定向–要完成请求必须进行更进一步的操作
  • 4xx:客户端错误–请求有语法错误或请求无法实现
  • 5xx:服务器端错误–服务器未能实现合法的请求

常见状态代码、状态描述、说明:

1**(信息类):表示接收到请求并且继续处理
100——客户必须继续发出请求
101——客户要求服务器根据请求转换HTTP协议版本,只能切换到更高级的协议

2**(响应成功):表示动作被成功接收、理解和接受
200——表明该请求被成功地完成,所请求的资源发送回客户端
201——提示知道新文件的URL
202——接受和处理、但处理未完成
203——返回信息不确定或不完整
204——请求收到,但返回信息为空
205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206——服务器已经完成了部分用户的GET请求

3**(重定向类):为了完成指定的动作,必须接受进一步处理
300——请求的资源可在多处得到
301——本网页被永久性转移到另一个URL
302——请求的网页被转移到一个新的地址,但客户访问仍继续通过原始URL地址,重定向,新的URL会在response中的Location中返回,浏览器将会使用新的URL发出新的Request
303——建议客户访问其他URL或访问方式
304——自从上次请求后,请求的网页未修改过,服务器返回此响应时,不会返回网页内容,代表上次的文档已经被缓存了,还可以继续使用
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除

4**(客户端错误类):请求包含错误语法或不能正确执行
400——客户端请求有语法错误,不能被服务器所理解
401——请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
402——保留有效ChargeTo头响应
403——禁止访问,服务器收到请求,但是拒绝提供服务
404——一个404错误表明可连接服务器,但服务器无法取得所请求的网页,请求资源不存在。eg:输入了错误的URL
405——用户在Request-Line字段定义的方法不允许
406——根据用户发送的Accept拖,请求资源不可访问
407——类似401,用户必须首先在代理服务器上得到授权
408——客户端没有在用户指定的饿时间内完成请求
409——对当前资源状态,请求不能完成
410——服务器上不再有此资源且无进一步的参考地址
411——服务器拒绝用户定义的Content-Length属性请求
412——一个或多个请求头字段在当前请求中错误
413——请求的资源大于服务器允许的大小
414——请求的资源URL长于服务器允许的长度
415——请求资源不支持请求项目格式
416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求长。

5**(服务端错误类):服务器不能正确执行一个正确的请求
500——服务器遇到错误,无法完成请求
501——未实现
502——网关错误
503——由于超载或停机维护,服务器目前无法使用,一段时间后可能恢复正常
504——充当网关或代理的服务器,未及时从远端服务器获取请求
505——服务器不支持请求的 HTTP 协议的版本,无法完成处 理

http2.0

  • 内容安全,基于 https
  • 提升访问速度
  • 允许多路复用
  • 二进制分帧
  • 首部压缩
  • 服务器端推送
1…121314…17
© 2021 小朱
由 Hexo 强力驱动
主题 - NexT.Pisces