更新文档
This commit is contained in:
35
.idea/deployment.xml
generated
Normal file
35
.idea/deployment.xml
generated
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PublishConfigData">
|
||||||
|
<serverData>
|
||||||
|
<paths name="192.168.0.199">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
<paths name="211.144.114.146">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
<paths name="211.144.114.147">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
<paths name="nodeJs">
|
||||||
|
<serverdata>
|
||||||
|
<mappings>
|
||||||
|
<mapping local="$PROJECT_DIR$" web="/" />
|
||||||
|
</mappings>
|
||||||
|
</serverdata>
|
||||||
|
</paths>
|
||||||
|
</serverData>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="PROJECT" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
16
.idea/misc.xml
generated
Normal file
16
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
<component name="SvnConfiguration" myUseAcceleration="nothing">
|
||||||
|
<configuration />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/weRequest.iml" filepath="$PROJECT_DIR$/.idea/weRequest.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
12
.idea/weRequest.iml
generated
Normal file
12
.idea/weRequest.iml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
281
.idea/workspace.xml
generated
Normal file
281
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="7fdaf425-8e35-4881-82a2-b5d2d5a275d9" name="Default" comment="">
|
||||||
|
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/weRequest.js" afterPath="$PROJECT_DIR$/src/weRequest.js" />
|
||||||
|
</list>
|
||||||
|
<ignored path="weRequest.iws" />
|
||||||
|
<ignored path=".idea/workspace.xml" />
|
||||||
|
<ignored path="$PROJECT_DIR$/.tmp/" />
|
||||||
|
<ignored path="$PROJECT_DIR$/temp/" />
|
||||||
|
<ignored path="$PROJECT_DIR$/tmp/" />
|
||||||
|
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||||
|
<option name="TRACKING_ENABLED" value="true" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="CreatePatchCommitExecutor">
|
||||||
|
<option name="PATCH_PATH" value="" />
|
||||||
|
</component>
|
||||||
|
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
|
||||||
|
<component name="FavoritesManager">
|
||||||
|
<favorites_list name="weRequest" />
|
||||||
|
</component>
|
||||||
|
<component name="FileEditorManager">
|
||||||
|
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
|
||||||
|
<file leaf-file-name="weRequest.js" pinned="false" current-in-tab="true">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/weRequest.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="385">
|
||||||
|
<caret line="238" column="26" selection-start-line="238" selection-start-column="26" selection-end-line="238" selection-end-column="26" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</file>
|
||||||
|
</leaf>
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="IdeDocumentHistory">
|
||||||
|
<option name="CHANGED_PATHS">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/src/weRequest.js" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||||
|
<component name="JsGulpfileManager">
|
||||||
|
<detection-done>true</detection-done>
|
||||||
|
<sorting>DEFINITION_ORDER</sorting>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectFrameBounds">
|
||||||
|
<option name="x" value="1912" />
|
||||||
|
<option name="y" value="76" />
|
||||||
|
<option name="width" value="1936" />
|
||||||
|
<option name="height" value="1096" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectView">
|
||||||
|
<navigator currentView="ProjectPane" proportions="" version="1">
|
||||||
|
<flattenPackages />
|
||||||
|
<showMembers />
|
||||||
|
<showModules />
|
||||||
|
<showLibraryContents />
|
||||||
|
<hideEmptyPackages />
|
||||||
|
<abbreviatePackageNames />
|
||||||
|
<autoscrollToSource />
|
||||||
|
<autoscrollFromSource />
|
||||||
|
<sortByType />
|
||||||
|
<manualOrder />
|
||||||
|
<foldersAlwaysOnTop value="true" />
|
||||||
|
</navigator>
|
||||||
|
<panes>
|
||||||
|
<pane id="Scope" />
|
||||||
|
<pane id="Scratches" />
|
||||||
|
<pane id="ProjectPane">
|
||||||
|
<subPane>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="weRequest" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="weRequest" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="weRequest" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
<PATH>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="weRequest" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="weRequest" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
<PATH_ELEMENT>
|
||||||
|
<option name="myItemId" value="src" />
|
||||||
|
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
|
||||||
|
</PATH_ELEMENT>
|
||||||
|
</PATH>
|
||||||
|
</subPane>
|
||||||
|
</pane>
|
||||||
|
</panes>
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="options.splitter.main.proportions" value="0.3" />
|
||||||
|
<property name="options.lastSelected" value="project.propVCSSupport.Mappings" />
|
||||||
|
<property name="options.splitter.details.proportions" value="0.2" />
|
||||||
|
<property name="options.searchVisible" value="true" />
|
||||||
|
<property name="last_opened_file_path" value="F:/weRequest_proj/trunk" />
|
||||||
|
<property name="WebServerToolWindowFactoryState" value="true" />
|
||||||
|
<property name="js-jscs-nodeInterpreter" value="C:\Program Files\nodejs\node.exe" />
|
||||||
|
</component>
|
||||||
|
<component name="RunManager">
|
||||||
|
<configuration default="true" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="DartTestRunConfigurationType" factoryName="Dart Test">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JavaScriptTestRunnerKarma" factoryName="Karma">
|
||||||
|
<config-file value="" />
|
||||||
|
<node-interpreter value="project" />
|
||||||
|
<envs />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="NodeJSConfigurationType" factoryName="Node.js" path-to-node="project" working-dir="">
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="cucumber.js" factoryName="Cucumber.js">
|
||||||
|
<option name="cucumberJsArguments" value="" />
|
||||||
|
<option name="executablePath" />
|
||||||
|
<option name="filePath" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
|
||||||
|
<node-interpreter>project</node-interpreter>
|
||||||
|
<node-options />
|
||||||
|
<gulpfile />
|
||||||
|
<tasks />
|
||||||
|
<arguments />
|
||||||
|
<envs />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
|
||||||
|
<command value="run-script" />
|
||||||
|
<scripts />
|
||||||
|
<node-interpreter value="project" />
|
||||||
|
<envs />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
<configuration default="true" type="mocha-javascript-test-runner" factoryName="Mocha">
|
||||||
|
<node-interpreter>project</node-interpreter>
|
||||||
|
<node-options />
|
||||||
|
<working-directory />
|
||||||
|
<pass-parent-env>true</pass-parent-env>
|
||||||
|
<envs />
|
||||||
|
<ui />
|
||||||
|
<extra-mocha-options />
|
||||||
|
<test-kind>DIRECTORY</test-kind>
|
||||||
|
<test-directory />
|
||||||
|
<recursive>false</recursive>
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component name="ShelveChangesManager" show_recycled="false">
|
||||||
|
<option name="remove_strategy" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="7fdaf425-8e35-4881-82a2-b5d2d5a275d9" name="Default" comment="" />
|
||||||
|
<created>1507876610387</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1507876610387</updated>
|
||||||
|
<workItem from="1507876611725" duration="6581000" />
|
||||||
|
<workItem from="1508476543568" duration="6000" />
|
||||||
|
<workItem from="1508748183486" duration="17000" />
|
||||||
|
<workItem from="1508748517669" duration="253000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TimeTrackingManager">
|
||||||
|
<option name="totallyTimeSpent" value="6857000" />
|
||||||
|
</component>
|
||||||
|
<component name="ToolWindowManager">
|
||||||
|
<frame x="1912" y="76" width="1936" height="1096" extended-state="6" />
|
||||||
|
<editor active="true" />
|
||||||
|
<layout>
|
||||||
|
<window_info id="Remote Host" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
|
||||||
|
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
|
||||||
|
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
|
||||||
|
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
|
||||||
|
</layout>
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.UiProperties">
|
||||||
|
<option name="RECENTLY_FILTERED_USER_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
<option name="RECENTLY_FILTERED_BRANCH_GROUPS">
|
||||||
|
<collection />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="VcsContentAnnotationSettings">
|
||||||
|
<option name="myLimit" value="2678400000" />
|
||||||
|
</component>
|
||||||
|
<component name="XDebuggerManager">
|
||||||
|
<breakpoint-manager />
|
||||||
|
<watches-manager />
|
||||||
|
</component>
|
||||||
|
<component name="editorHistoryManager">
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/weRequest.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/weRequest.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/weRequest.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="0">
|
||||||
|
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
<entry file="file://$PROJECT_DIR$/src/weRequest.js">
|
||||||
|
<provider selected="true" editor-type-id="text-editor">
|
||||||
|
<state relative-caret-position="385">
|
||||||
|
<caret line="238" column="26" selection-start-line="238" selection-start-column="26" selection-end-line="238" selection-end-column="26" />
|
||||||
|
<folding />
|
||||||
|
</state>
|
||||||
|
</provider>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
228
README.md
228
README.md
@@ -1,8 +1,22 @@
|
|||||||
# 登录时序图
|
<img src="image/logo.png" alt="logo" height="160" align="center" />
|
||||||

|
|
||||||
|
# weRequest
|
||||||
|
|
||||||
|
_解决繁琐的小程序会话管理,一款自带登录态管理的网络请求组件。_
|
||||||
|
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
[]()
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
上图是小程序官方文档中的**登录时序图**。此图涵盖了前后端,详细讲解了包括登录态的生成,维护,传输等各方面的问题。
|
上图是小程序官方文档中的**登录时序图**。此图涵盖了前后端,详细讲解了包括登录态的生成,维护,传输等各方面的问题。
|
||||||
# 发起网络请求的流程图
|
|
||||||
具体到业务开发过程中的前端来说,我认为上图还不够完整,于是我画了下面这张以**前端逻辑**为出发点的、包含循环的**流程图**。
|
具体到业务开发过程中的前端来说,我认为上图还不够完整,于是我画了下面这张以**前端逻辑**为出发点的、包含循环的**流程图**。
|
||||||
我认为前端每一次**发起网络请求**,跟后台进行数据交互,都适用于下图的**流程**:
|
我认为前端每一次**发起网络请求**,跟后台进行数据交互,都适用于下图的**流程**:
|
||||||

|

|
||||||
@@ -10,6 +24,7 @@
|
|||||||
- **hasChecked:** 用一状态标识本生命周期内是否执行过`wx.checkSession`,判断该标识,若否,开始执行`wx.checkSession`,若是,进入下一步
|
- **hasChecked:** 用一状态标识本生命周期内是否执行过`wx.checkSession`,判断该标识,若否,开始执行`wx.checkSession`,若是,进入下一步
|
||||||
- **wx.checkSession():** 调用接口判断登录态是否过期,若是,重新登录;若否,进入下一步
|
- **wx.checkSession():** 调用接口判断登录态是否过期,若是,重新登录;若否,进入下一步
|
||||||
> wx.checkSession()是小程序提供的检测登录态是否过期的接口,生命周期内只需调用一次即可。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明
|
> wx.checkSession()是小程序提供的检测登录态是否过期的接口,生命周期内只需调用一次即可。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明
|
||||||
|
|
||||||
- **wx.getStorage(session):** 尝试获取本地的`session`。如果之前曾经登录过,则能获取到;否则,本地无`session`
|
- **wx.getStorage(session):** 尝试获取本地的`session`。如果之前曾经登录过,则能获取到;否则,本地无`session`
|
||||||
- **wx.login():** 小程序提供的接口,用于获取`code`(code有效期为5分钟)
|
- **wx.login():** 小程序提供的接口,用于获取`code`(code有效期为5分钟)
|
||||||
- **wx.request(code):** 将`code`通过后台提供的接口,换取`session`
|
- **wx.request(code):** 将`code`通过后台提供的接口,换取`session`
|
||||||
@@ -17,16 +32,13 @@
|
|||||||
- **wx.request(session):** 真正发起业务请求,请求中带上`session`
|
- **wx.request(session):** 真正发起业务请求,请求中带上`session`
|
||||||
- **parse(data):** 对后台返回的数据进行预解析,若发现登录态失效,则重新执行登录;若成功,则真正获取到业务数据
|
- **parse(data):** 对后台返回的数据进行预解析,若发现登录态失效,则重新执行登录;若成功,则真正获取到业务数据
|
||||||
|
|
||||||
# 拓展小程序网络请求的能力
|
只要遵循上图的流程,我们就无需在业务逻辑中关注登录态的问题了,相当于把登录态的管理问题**耦合**到了发起网络请求当中,本组件则完成了上述流程的封装,让开发者不用再关心以上逻辑,把精力放回在业务的开发上。
|
||||||
只要遵循上图的流程,我们就无需在业务逻辑中关注登录态的问题了,相当于把登录态的管理问题**耦合**到了发起网络请求当中。
|
|
||||||
一般情况下,我们程序设计都会遵循模块解耦的原则,尽可能将模块颗粒化到最小。这导致可能有些同学认为模块耦合不是好事情,但是我认为这是要分情况的:
|
## 目标
|
||||||
- 小程序区别与传统的H5,不支持cookies,在代码层级上讲,这无形中就给登录态的管理增加了复杂度:cookies会在H5的每个请求中自动带上,但小程序的请求却每次都需要手动带上登录态参数
|
让业务逻辑更专注,不用再关注底层登录态问题。小程序对比以往的H5,登录态管理逻辑要复杂很多。通过`weRequest`这个组件,希望能帮助开发者把更多精力放在业务逻辑上,而登录态管理问题只需通过一次简单配置,以后就不用再花精力管理了。
|
||||||
- 小程序区别于基于公众号登录的H5来说,又存在一定的优势:登录授权时并不需要多次的页面跳转(Oauth),也正因为如此,小程序的请求在登录态失效时,需要具备重新登录并自动重试请求的能力(无页面刷新感,用户甚至都不能感知到进行了重新登录)
|
|
||||||
|
## 怎么使用
|
||||||
|
|
||||||
以上两点虽然是登录态管理的问题,但从另外一个角度去理解,我更认为它是小程序网络请求的能力问题,所以,我认为**通过拓展小程序网络请求能力来实现登录态的自动管理**是非常合适的。
|
|
||||||
# 通用组件——weRequest
|
|
||||||
一个通过拓展`wx.request`,从而实现自动管理登录态的组件。
|
|
||||||
先来看看怎么使用:
|
|
||||||
```javascript
|
```javascript
|
||||||
var weRequest= require('../weRequest');
|
var weRequest= require('../weRequest');
|
||||||
|
|
||||||
@@ -51,87 +63,213 @@ weRequest.request({
|
|||||||
- 初始化组件配置
|
- 初始化组件配置
|
||||||
- **就像使用`wx.request`那样去使用它**
|
- **就像使用`wx.request`那样去使用它**
|
||||||
|
|
||||||
## 自动带上登录态参数
|
## 演示DEMO
|
||||||
我们来看看执行上面代码的DEMO效果:
|
|
||||||

|
### 自动带上登录态参数
|
||||||
|

|
||||||
|
|
||||||
可以看到,通过`weRequest`发出的请求,将会自动带上登录态参数。
|
可以看到,通过`weRequest`发出的请求,将会自动带上登录态参数。
|
||||||
对应的流程为下图中**红色**的指向:
|
对应的流程为下图中**红色**的指向:
|
||||||

|

|
||||||
|
|
||||||
## 没有登录态时,自动登录
|
### 没有登录态时,自动登录
|
||||||
那如果当前小程序并没有登录态的情况又会如何呢?
|

|
||||||
接下来我们来看看本地无登录态情况下的模拟:
|
|
||||||

|
|
||||||
|
|
||||||
当本地没有登录态时,按照流程图,`weRequest`将会自动执行`wx.login()`后的一系列流程,得到`code`并调用后台接口换取`session`,储存在localStorage之后,重新发起业务请求。
|
当本地没有登录态时,按照流程图,`weRequest`将会自动执行`wx.login()`后的一系列流程,得到`code`并调用后台接口换取`session`,储存在localStorage之后,重新发起业务请求。
|
||||||
对应的流程为下图中**红色**的指向:
|
对应的流程为下图中**红色**的指向:
|
||||||

|

|
||||||
|
|
||||||
## 登录态过期时,自动重新登录
|
### 登录态过期时,自动重新登录
|
||||||
接下来我们再来看看,当本地储存的登录态过期之后,页面的行为如何:
|

|
||||||

|
|
||||||
|
|
||||||
对后台数据进行预解析之后,发现登录态过期,于是重新执行登录流程,获取新的`session`之后,重新发起请求。
|
对后台数据进行预解析之后,发现登录态过期,于是重新执行登录流程,获取新的`session`之后,重新发起请求。
|
||||||
对应的流程为下图中**红色**的指向:
|
对应的流程为下图中**红色**的指向:
|
||||||

|

|
||||||
|
|
||||||
|
## 文档
|
||||||
|
|
||||||
|
### .init(OBJECT)
|
||||||
|
|
||||||
|
对组件进行初始化配置,使用组件发起请求前必须进行至少一次的配置
|
||||||
|
|
||||||
|
#### OBJECT参数说明
|
||||||
|
|
||||||
|
|参数名|类型|必填|默认值|说明|
|
||||||
|
| :-------- | :-------| :------ | :------ |:------ |
|
||||||
|
|sessionName|String|否|session|储存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不配置,默认为session|
|
||||||
|
|urlPerfix|String|否||请求URL的固定前缀,如果配置了,后续请求的URL都会自动加上这个前缀|
|
||||||
|
|loginTrigger|Function|是||触发重新登录的条件;参数为CGI返回的数据,返回需要重新登录的条件|
|
||||||
|
|codeToSession|Object|是||用code换取session的CGI配置|
|
||||||
|
|reLoginLimit|Int|否|3|登录重试次数,当连续请求登录接口返回失败次数超过这个次数,将不再重试登录|
|
||||||
|
|successTrigger|Function|是||触发请求成功的条件;参数为CGI返回的数据,返回接口逻辑成功的条件|
|
||||||
|
|successData|Function|否||成功之后返回数据;参数为CGI返回的数据,返回逻辑需要使用的数据|
|
||||||
|
|errorTitle|String/Function|否|操作失败|接口逻辑失败时,错误弹窗的标题|
|
||||||
|
|errorContent|String/Function|否||接口逻辑失败时,错误弹窗的内容|
|
||||||
|
|errorCallback|Function|否||当出现接口逻辑错误时,会执行统一的回调函数,这里可以做统一的错误上报等处理|
|
||||||
|
|doNotCheckSession|Boolean|否|false|是否需要调用checkSession,验证小程序的登录态过期;若业务不需要使用到session_key,则可配置为true|
|
||||||
|
|reportCGI|Function|否||接口返回成功之后,会执行统一的回调函数,这里可以做统一的耗时上报等处理|
|
||||||
|
|mockJson|Object|否||可为接口提供mock数据|
|
||||||
|
|globalData|Object/Function|否||所有请求都会自动带上这里的参数|
|
||||||
|
|
||||||
|
##### codeToSession参数说明
|
||||||
|
|
||||||
|
|参数名|类型|必填|默认值|说明|
|
||||||
|
| :-------- | :-------| :------ | :------ |:------ |
|
||||||
|
|url|String|是||CGI的url|
|
||||||
|
|method|String|否|GET|调用改CGI的方法|
|
||||||
|
|codeName|String|否|code|CGI中传参时,存放code的名称|
|
||||||
|
|data|Object|否||登录接口需要的其他参数|
|
||||||
|
|success|Function|是||接口返回成功的函数;需要返回session的值|
|
||||||
|
|fail|Function|否||code换取session的接口逻辑出错时,执行的函数,若配置了此函数,则不再默认弹窗报错|
|
||||||
|
|
||||||
|
##### reportCGI返回参数说明
|
||||||
|
|参数名|类型|说明|
|
||||||
|
| :-------- | :-------| :------ |
|
||||||
|
|name|String|调用的接口名字,可在request接口的report字段配置|
|
||||||
|
|startTime|Int|发起请求时的时间戳|
|
||||||
|
|endTime|Int|请求返回时的时间戳|
|
||||||
|
|request|Function|请求方法,可用于上报|
|
||||||
|
|
||||||
|
#### 示例代码
|
||||||
|
|
||||||
## 组件的配置项
|
|
||||||
`weRequest`提供一个`init`方法,用于对组件的配置,以下展示所有的配置项:
|
|
||||||
```javascript
|
```javascript
|
||||||
weRequest.init({
|
weRequest.init({
|
||||||
// 储存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不传,默认为session
|
|
||||||
sessionName: "session",
|
sessionName: "session",
|
||||||
// 请求URL的固定前缀;可不传,默认为空
|
|
||||||
urlPerfix: "https://www.example.com/",
|
urlPerfix: "https://www.example.com/",
|
||||||
// 触发重新登录的条件,res为CGI返回的数据
|
// 触发重新登录的条件,res为CGI返回的数据
|
||||||
loginTrigger: function (res) {
|
loginTrigger: function (res) {
|
||||||
// 此处例子:当返回数据中的字段errcode等于-1,会自动触发重新登录
|
// 此处例子:当返回数据中的字段errcode等于-1,会自动触发重新登录
|
||||||
return res.errcode == -1;
|
return res.errcode == -1;
|
||||||
},
|
},
|
||||||
// 用code换取session的CGI配置
|
|
||||||
codeToSession: {
|
codeToSession: {
|
||||||
// CGI的URL
|
|
||||||
url: 'user/login',
|
url: 'user/login',
|
||||||
// 调用改CGI的方法;可不传,默认为GET
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
// CGI中传参时,存放code的名称,此处例子名称就是code;可不传,默认值为code
|
|
||||||
codeName: 'code',
|
codeName: 'code',
|
||||||
|
data: {},
|
||||||
// CGI中返回的session值
|
// CGI中返回的session值
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
// 此处例子:CGI返回数据中的字段session即为session值
|
// 此处例子:CGI返回数据中的字段session即为session值
|
||||||
return res.session;
|
return res.session;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 登录重试次数,当连续请求登录接口返回失败次数超过这个次数,将不再重试登录
|
|
||||||
reLoginLimit: 2,
|
reLoginLimit: 2,
|
||||||
// 触发请求成功的条件
|
|
||||||
successTrigger: function (res) {
|
successTrigger: function (res) {
|
||||||
// 此处例子:当返回数据中的字段errcode等于0时,代表请求成功,其他情况都认为业务逻辑失败
|
// 此处例子:当返回数据中的字段errcode等于0时,代表请求成功,其他情况都认为业务逻辑失败
|
||||||
return res.errcode == 0;
|
return res.errcode == 0;
|
||||||
},
|
},
|
||||||
// 成功之后返回数据;可不传
|
|
||||||
successData: function (res) {
|
successData: function (res) {
|
||||||
// 此处例子:返回数据中的字段data为业务接受到的数据
|
// 此处例子:返回数据中的字段data为业务接受到的数据
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
// 当CGI返回错误时,弹框提示的标题文字
|
|
||||||
errorTitle: function(res) {
|
errorTitle: function(res) {
|
||||||
// 此处例子:当返回数据中的字段errcode等于0x10040730时,错误弹框的标题是“温馨提示”,其他情况下则是“操作失败”
|
// 此处例子:当返回数据中的字段errcode等于0x10040730时,错误弹框的标题是“温馨提示”,其他情况下则是“操作失败”
|
||||||
return res.errcode == 0x10040730 ? '温馨提示' : '操作失败'
|
return res.errcode == 0x10040730 ? '温馨提示' : '操作失败'
|
||||||
},
|
},
|
||||||
// 当CGI返回错误时,弹框提示的内容文字
|
|
||||||
errorContent: function(res) {
|
errorContent: function(res) {
|
||||||
// 此处例子:返回数据中的字段msg为错误弹框的提示内容文字
|
// 此处例子:返回数据中的字段msg为错误弹框的提示内容文字
|
||||||
return res.msg
|
return res.msg
|
||||||
|
},
|
||||||
|
errorCallback: function(obj, res) {
|
||||||
|
// do some report
|
||||||
|
},
|
||||||
|
doNotCheckSession: true,
|
||||||
|
// 上报耗时的函数,name为上报名称,startTime为接口调用开始时的时间戳,endTime为接口返回时的时间戳
|
||||||
|
reportCGI: function(name, startTime, endTime, request) {
|
||||||
|
// 这里可以自行上报耗时
|
||||||
|
//wx.reportAnalytics(name, {
|
||||||
|
// time: endTime - startTime
|
||||||
|
//});
|
||||||
|
//request({
|
||||||
|
// url: 'reportCGI',
|
||||||
|
// data: {
|
||||||
|
// name: name,
|
||||||
|
// cost: endTime - startTime
|
||||||
|
// },
|
||||||
|
// fail: function() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//})
|
||||||
|
console.log(name + ":" + (endTime - startTime));
|
||||||
|
},
|
||||||
|
mockJson: require("../../mock.json"),
|
||||||
|
globalData: function() {
|
||||||
|
return {
|
||||||
|
version: getApp().version
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
# 让业务逻辑更专注,不用再关注底层登录态问题
|
|
||||||
小程序对比以往的H5,登录态管理逻辑要复杂很多。通过`weRequest`这个组件,希望能帮助开发者把更多精力放在业务逻辑上,而登录态管理问题只需通过一次简单配置,以后就不用再花精力管理了。
|
|
||||||
|
|
||||||
# FAQ
|
### .request(OBJECT)
|
||||||
## 我希望在请求时候,页面能出现最简单的loading状态,该怎么办?
|
|
||||||
|
带上登录态发起一个请求,参数大部分与`wx.request`一致
|
||||||
|
|
||||||
|
#### OBJECT参数说明
|
||||||
|
|
||||||
|
|参数名|类型|必填|默认值|说明|是否与wx.request不一致|
|
||||||
|
| :-------- | :-------| :------ | :------ |:------ |:------ |
|
||||||
|
|url|String|是||开发者服务器接口地址,若在init()时有配置urlPerfix,则这里会自动拼接前缀|是|
|
||||||
|
|data|Object/String|否||请求的参数||
|
||||||
|
|header|Object|否||设置请求的 header,header 中不能设置 Referer。||
|
||||||
|
|method|String|否|GET|(需大写)有效值:OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT||
|
||||||
|
|dataType|String|否|json|如果设为json,会尝试对返回的数据做一次 JSON.parse||
|
||||||
|
|beforeSend|Function|否||发起请求前执行的函数|是|
|
||||||
|
|success|Function|否||收到开发者服务成功返回,且执行`successTrigger`成功后的回调函数,参数为`successData`返回的参数|是|
|
||||||
|
|fail|Function|否||接口调用失败,或执行`successTrigger`失败后的回调函数,若这里有配置,则不再默认弹窗报错|是|
|
||||||
|
|complete|Function|否||接口调用结束的回调函数(调用成功、失败都会执行)||
|
||||||
|
|showLoading|Boolean|否|false|请求过程页面是否展示全屏的loading|是|
|
||||||
|
|report|String|否||接口请求成功后将自动执行init()中配置的reportCGI函数,其中的name字段值为这里配置的值|是|
|
||||||
|
|
||||||
|
#### 示例代码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
weRequest.request({
|
||||||
|
url: 'order/detail',
|
||||||
|
showLoading: true,
|
||||||
|
report: 'detail',
|
||||||
|
data: {
|
||||||
|
id: '123'
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
fail: function(obj, res) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### .uploadFile(Object)
|
||||||
|
|
||||||
|
带上登录态,将本地资源上传到开发者服务器,客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data,参数大部分与`wx.uploadFile`一致
|
||||||
|
|
||||||
|
#### OBJECT参数说明
|
||||||
|
|
||||||
|
|参数名|类型|必填|默认值|说明|是否与wx.uploadFile不一致|
|
||||||
|
| :-------- | :-------| :------ | :------ |:------ |:------ |
|
||||||
|
|url|String|是||开发者服务器接口地址,若在init()时有配置urlPerfix,则这里会自动拼接前缀|是|
|
||||||
|
|filePath|String|是||要上传文件资源的路径||
|
||||||
|
|name|String|是||文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容||
|
||||||
|
|header|Object|否||设置请求的 header,header 中不能设置 Referer。||
|
||||||
|
|formData|Object|否||HTTP 请求中其他额外的 form data||
|
||||||
|
|beforeSend|Function|否||发起请求前执行的函数|是|
|
||||||
|
|success|Function|否||收到开发者服务成功返回,且执行`successTrigger`成功后的回调函数,参数为`successData`返回的参数|是|
|
||||||
|
|fail|Function|否||接口调用失败,或执行`successTrigger`失败后的回调函数,若这里有配置,则不再默认弹窗报错|是|
|
||||||
|
|complete|Function|否||接口调用结束的回调函数(调用成功、失败都会执行)||
|
||||||
|
|showLoading|Boolean|否|false|请求过程页面是否展示全屏的loading|是|
|
||||||
|
|report|String|否||接口请求成功后将自动执行init()中配置的reportCGI函数,其中的name字段值为这里配置的值|是|
|
||||||
|
|
||||||
|
### .login()
|
||||||
|
|
||||||
|
<font color=red>[不建议使用]</font> 在不发起业务请求的情况下,单独执行登录逻辑
|
||||||
|
|
||||||
|
### .setSession(String)
|
||||||
|
|
||||||
|
<font color=red>[不建议使用]</font> 设置用户票据的值
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### 我希望在请求时候,页面能出现最简单的loading状态,该怎么办?
|
||||||
|
|
||||||
只需要在请求的时候,加上参数`showLoading: true`即可,如:
|
只需要在请求的时候,加上参数`showLoading: true`即可,如:
|
||||||
```javascript
|
```javascript
|
||||||
weRequest.request({
|
weRequest.request({
|
||||||
@@ -147,7 +285,8 @@ weRequest.request({
|
|||||||
```
|
```
|
||||||
当然,如果你希望使用个性化的loading样式,你可以直接使用beforeSend参数来进行自定义展示个性化的loading,并且在complete的时候将它隐藏。
|
当然,如果你希望使用个性化的loading样式,你可以直接使用beforeSend参数来进行自定义展示个性化的loading,并且在complete的时候将它隐藏。
|
||||||
|
|
||||||
## 某些请求在返回错误时,我不希望触发通用的错误提示框,而想用特别的逻辑去处理,该怎么办?
|
### 某些请求在返回错误时,我不希望触发通用的错误提示框,而想用特别的逻辑去处理,该怎么办?
|
||||||
|
|
||||||
只需要在请求的时候,加上参数`fail: function(){ ... }`即可,如:
|
只需要在请求的时候,加上参数`fail: function(){ ... }`即可,如:
|
||||||
```javascript
|
```javascript
|
||||||
weRequest.request({
|
weRequest.request({
|
||||||
@@ -166,7 +305,8 @@ weRequest.request({
|
|||||||
```
|
```
|
||||||
此时,如果接口返回错误码,将触发这里定义的fail函数,且默认错误弹框将不会出现。
|
此时,如果接口返回错误码,将触发这里定义的fail函数,且默认错误弹框将不会出现。
|
||||||
|
|
||||||
## 为什么工具在发起请求之前,不主动去判断第三方session是否过期,而要通过接口结果来判断,这不是浪费了一次请求往返吗?
|
### 为什么工具在发起请求之前,不主动去判断第三方session是否过期,而要通过接口结果来判断,这不是浪费了一次请求往返吗?
|
||||||
|
|
||||||
每个小程序对于自身生成的session都有自己的一套管理方案,微信官方也没有指明一套通用的方案来要求开发者,仅仅要求了**应该保证其安全性且不应该设置较长的过期时间**。
|
每个小程序对于自身生成的session都有自己的一套管理方案,微信官方也没有指明一套通用的方案来要求开发者,仅仅要求了**应该保证其安全性且不应该设置较长的过期时间**。
|
||||||
原文如下:
|
原文如下:
|
||||||
>通过 wx.login() 获取到用户登录态之后,需要维护登录态。开发者要注意不应该直接把 session_key、openid 等字段作为用户的标识或者 session 的标识,而应该自己派发一个 session 登录态(请参考登录时序图)。对于开发者自己生成的 session,应该保证其安全性且不应该设置较长的过期时间。session 派发到小程序客户端之后,可将其存储在 storage ,用于后续通信使用。
|
>通过 wx.login() 获取到用户登录态之后,需要维护登录态。开发者要注意不应该直接把 session_key、openid 等字段作为用户的标识或者 session 的标识,而应该自己派发一个 session 登录态(请参考登录时序图)。对于开发者自己生成的 session,应该保证其安全性且不应该设置较长的过期时间。session 派发到小程序客户端之后,可将其存储在 storage ,用于后续通信使用。
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,9 +1,9 @@
|
|||||||
var weRequest = require('../src/weRequest');
|
var weRequest = require('../src/weRequest');
|
||||||
|
|
||||||
weRequest.init({
|
weRequest.init({
|
||||||
// 存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不传,默认为session
|
// 存在localStorage的session名称,且CGI请求的data中会自动带上以此为名称的session值;可不配置,默认为session
|
||||||
sessionName: "session",
|
sessionName: "session",
|
||||||
// 请求URL的固定前缀;可不传,默认为空
|
// 请求URL的固定前缀;可不配置,默认为空
|
||||||
urlPerfix: "https://www.example.com/",
|
urlPerfix: "https://www.example.com/",
|
||||||
// 触发重新登录的条件,res为CGI返回的数据
|
// 触发重新登录的条件,res为CGI返回的数据
|
||||||
loginTrigger: function (res) {
|
loginTrigger: function (res) {
|
||||||
@@ -14,11 +14,11 @@ weRequest.init({
|
|||||||
codeToSession: {
|
codeToSession: {
|
||||||
// CGI的URL
|
// CGI的URL
|
||||||
url: 'user/login',
|
url: 'user/login',
|
||||||
// 调用改CGI的方法;可不传,默认为GET
|
// 调用改CGI的方法;可不配置,默认为GET
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
// CGI中传参时,存放code的名称,此处例子名称就是code;可不传,默认值为code
|
// CGI中传参时,存放code的名称,此处例子名称就是code;可不配置,默认值为code
|
||||||
codeName: 'code',
|
codeName: 'code',
|
||||||
// 登录接口需要的其他参数;可不传,默认为{}
|
// 登录接口需要的其他参数;可不配置,默认为{}
|
||||||
data: {},
|
data: {},
|
||||||
// CGI中返回的session值
|
// CGI中返回的session值
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
@@ -33,7 +33,7 @@ weRequest.init({
|
|||||||
// 此处例子:当返回数据中的字段errcode等于0时,代表请求成功,其他情况都认为业务逻辑失败
|
// 此处例子:当返回数据中的字段errcode等于0时,代表请求成功,其他情况都认为业务逻辑失败
|
||||||
return res.errcode == 0;
|
return res.errcode == 0;
|
||||||
},
|
},
|
||||||
// 成功之后返回数据;可不传
|
// 成功之后返回数据;可不配置
|
||||||
successData: function (res) {
|
successData: function (res) {
|
||||||
// 此处例子:返回数据中的字段data为业务接受到的数据
|
// 此处例子:返回数据中的字段data为业务接受到的数据
|
||||||
return res.data;
|
return res.data;
|
||||||
@@ -52,8 +52,37 @@ weRequest.init({
|
|||||||
errorCallback: function(obj, res) {
|
errorCallback: function(obj, res) {
|
||||||
// do some report
|
// do some report
|
||||||
},
|
},
|
||||||
// 是否需要调用checkSession,验证小程序的登录态过期,可不传,默认为false
|
// 当出现CGI错误时,统一的回调函数,这里可以做统一的错误上报等处理
|
||||||
doNotCheckSession: true
|
errorCallback: function(obj, res) {
|
||||||
|
// do some report
|
||||||
|
},
|
||||||
|
// 是否需要调用checkSession,验证小程序的登录态过期,可不配置,默认为false
|
||||||
|
doNotCheckSession: true,
|
||||||
|
// 上报耗时的函数,name为上报名称,startTime为接口调用开始时的时间戳,endTime为接口返回时的时间戳
|
||||||
|
reportCGI: function(name, startTime, endTime, request) {
|
||||||
|
//wx.reportAnalytics(name, {
|
||||||
|
// time: endTime - startTime
|
||||||
|
//});
|
||||||
|
//request({
|
||||||
|
// url: 'reportCGI',
|
||||||
|
// data: {
|
||||||
|
// name: name,
|
||||||
|
// cost: endTime - startTime
|
||||||
|
// },
|
||||||
|
// fail: function() {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//})
|
||||||
|
console.log(name + ":" + (endTime - startTime));
|
||||||
|
},
|
||||||
|
// 提供接口的mock,若不需使用,请设置为false
|
||||||
|
mockJson: require("../../mock.json"),
|
||||||
|
// 所有请求都会自动带上globalData里的参数
|
||||||
|
globalData: function() {
|
||||||
|
return {
|
||||||
|
version: getApp().version
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = weRequest;
|
module.exports = weRequest;
|
||||||
BIN
image/logo.png
Normal file
BIN
image/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
177
src/weRequest.js
177
src/weRequest.js
@@ -11,17 +11,28 @@ var errorTitle = "操作失败";
|
|||||||
var errorContent = function(res) {return res};
|
var errorContent = function(res) {return res};
|
||||||
var reLoginLimit = 3;
|
var reLoginLimit = 3;
|
||||||
var errorCallback = null;
|
var errorCallback = null;
|
||||||
|
var reportCGI = false;
|
||||||
|
var mockJson = false;
|
||||||
|
var globalData = false;
|
||||||
|
|
||||||
//global data
|
//global data
|
||||||
var session = '';
|
var session = '';
|
||||||
var sessionIsFresh = false;
|
var sessionIsFresh = false;
|
||||||
// 正在登录中,其他请求轮询稍后,避免重复调用登录接口
|
// 正在登录中,其他请求轮询稍后,避免重复调用登录接口
|
||||||
var logining = false;
|
var logining = false;
|
||||||
|
// 正在查询session有效期中,避免重复调用接口
|
||||||
|
var isCheckingSession = false;
|
||||||
|
|
||||||
function checkSession(callback, obj) {
|
function checkSession(callback, obj) {
|
||||||
if (!sessionIsFresh) {
|
if(isCheckingSession) {
|
||||||
|
setTimeout(function() {
|
||||||
|
checkSession(callback, obj)
|
||||||
|
}, 500);
|
||||||
|
} else if (!sessionIsFresh && session) {
|
||||||
|
isCheckingSession = true;
|
||||||
obj.count ++;
|
obj.count ++;
|
||||||
// 如果还没检验过session是否有效,则需要检验一次
|
// 如果还没检验过session是否有效,则需要检验一次
|
||||||
|
obj._checkSessionStartTime = new Date().getTime();
|
||||||
wx.checkSession({
|
wx.checkSession({
|
||||||
success: function () {
|
success: function () {
|
||||||
// 登录态有效,且在本生命周期内无须再检验了
|
// 登录态有效,且在本生命周期内无须再检验了
|
||||||
@@ -32,7 +43,12 @@ function checkSession(callback, obj) {
|
|||||||
session = '';
|
session = '';
|
||||||
},
|
},
|
||||||
complete: function () {
|
complete: function () {
|
||||||
|
isCheckingSession = false;
|
||||||
obj.count --;
|
obj.count --;
|
||||||
|
obj._checkSessionEndTime = new Date().getTime();
|
||||||
|
if(typeof reportCGI == "function") {
|
||||||
|
reportCGI('wx_checkSession', obj._checkSessionStartTime, obj._checkSessionEndTime, request);
|
||||||
|
}
|
||||||
doLogin(callback, obj);
|
doLogin(callback, obj);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -50,14 +66,21 @@ function doLogin(callback, obj) {
|
|||||||
// 正在登录中,请求轮询稍后,避免重复调用登录接口
|
// 正在登录中,请求轮询稍后,避免重复调用登录接口
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
doLogin(callback, obj);
|
doLogin(callback, obj);
|
||||||
}, 300)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
// 缓存中无session
|
// 缓存中无session
|
||||||
logining = true;
|
logining = true;
|
||||||
obj.count ++;
|
obj.count ++;
|
||||||
|
// 记录调用wx.login前的时间戳
|
||||||
|
obj._loginStartTime = new Date().getTime();
|
||||||
wx.login({
|
wx.login({
|
||||||
complete: function () {
|
complete: function () {
|
||||||
obj.count --;
|
obj.count --;
|
||||||
|
// 记录wx.login返回数据后的时间戳,用于上报
|
||||||
|
obj._loginEndTime = new Date().getTime();
|
||||||
|
if(typeof reportCGI == "function") {
|
||||||
|
reportCGI('wx_login', obj._loginStartTime, obj._loginEndTime, request);
|
||||||
|
}
|
||||||
typeof obj.complete == "function" && obj.count == 0 && obj.complete();
|
typeof obj.complete == "function" && obj.count == 0 && obj.complete();
|
||||||
},
|
},
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
@@ -77,6 +100,7 @@ function doLogin(callback, obj) {
|
|||||||
data: data,
|
data: data,
|
||||||
method: codeToSession.method,
|
method: codeToSession.method,
|
||||||
isLogin: true,
|
isLogin: true,
|
||||||
|
report: codeToSession.report || codeToSession.url,
|
||||||
success: function (s) {
|
success: function (s) {
|
||||||
session = s;
|
session = s;
|
||||||
sessionIsFresh = true;
|
sessionIsFresh = true;
|
||||||
@@ -90,27 +114,20 @@ function doLogin(callback, obj) {
|
|||||||
obj.count --;
|
obj.count --;
|
||||||
typeof obj.complete == "function" && obj.count == 0 && obj.complete();
|
typeof obj.complete == "function" && obj.count == 0 && obj.complete();
|
||||||
logining = false;
|
logining = false;
|
||||||
}
|
},
|
||||||
|
fail: codeToSession.fail || null
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
wx.showModal({
|
fail(obj, res);
|
||||||
title: '登录失败',
|
|
||||||
content: '请稍后重试',
|
|
||||||
showCancel: false
|
|
||||||
})
|
|
||||||
console.error(res);
|
console.error(res);
|
||||||
// 登录失败,解除锁,防止死循环
|
// 登录失败,解除锁,防止死锁
|
||||||
logining = false;
|
logining = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: function (res) {
|
fail: function (res) {
|
||||||
wx.showModal({
|
fail(obj, res);
|
||||||
title: '登录失败',
|
|
||||||
content: res.errMsg || '请稍后重试',
|
|
||||||
showCancel: false
|
|
||||||
})
|
|
||||||
console.error(res);
|
console.error(res);
|
||||||
// 登录失败,解除锁,防止死循环
|
// 登录失败,解除锁,防止死锁
|
||||||
logining = false;
|
logining = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -151,16 +168,27 @@ function request(obj) {
|
|||||||
obj.data = {};
|
obj.data = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.url != codeToSession.url) {
|
if (obj.url != codeToSession.url && session) {
|
||||||
obj.data[sessionName] = session;
|
obj.data[sessionName] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有全局参数,则添加
|
||||||
|
var gd = {};
|
||||||
|
if(typeof globalData == "function") {
|
||||||
|
gd = globalData();
|
||||||
|
} else if(typeof globalData == "object") {
|
||||||
|
gd = globalData;
|
||||||
|
}
|
||||||
|
obj.data = Object.assign({}, gd, obj.data);
|
||||||
|
|
||||||
obj.method = obj.method || 'GET';
|
obj.method = obj.method || 'GET';
|
||||||
|
|
||||||
// 如果请求的URL中不是http开头的,则自动添加配置中的前缀
|
// 如果请求的URL中不是http开头的,则自动添加配置中的前缀
|
||||||
var url = obj.url.startsWith('http') ? obj.url : (urlPerfix + obj.url);
|
var url = obj.url.startsWith('http') ? obj.url : (urlPerfix + obj.url);
|
||||||
// 如果请求不是GET,则在URL中自动加上登录态
|
// 如果请求不是GET,则在URL中自动加上登录态和全局参数
|
||||||
if(obj.method != "GET") {
|
if(obj.method != "GET") {
|
||||||
|
|
||||||
|
if(session) {
|
||||||
if(url.indexOf('?') >= 0) {
|
if(url.indexOf('?') >= 0) {
|
||||||
url += '&' + sessionName + '=' + session;
|
url += '&' + sessionName + '=' + session;
|
||||||
} else {
|
} else {
|
||||||
@@ -168,6 +196,21 @@ function request(obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有全局参数,则在URL中添加
|
||||||
|
for(var i in gd) {
|
||||||
|
if(url.indexOf('?') >= 0) {
|
||||||
|
url += '&' + i + '=' + gd[i];
|
||||||
|
} else {
|
||||||
|
url += '?' + i + '=' + gd[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有上报字段配置,则记录请求发出前的时间戳
|
||||||
|
if(obj.report) {
|
||||||
|
obj._reportStartTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
wx.request({
|
wx.request({
|
||||||
url: url,
|
url: url,
|
||||||
data: obj.data,
|
data: obj.data,
|
||||||
@@ -176,6 +219,13 @@ function request(obj) {
|
|||||||
dataType: obj.dataType || 'json',
|
dataType: obj.dataType || 'json',
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
if (res.statusCode == 200) {
|
if (res.statusCode == 200) {
|
||||||
|
|
||||||
|
// 如果有上报字段配置,则记录请求返回后的时间戳,并进行上报
|
||||||
|
if(obj.report && typeof reportCGI == "function") {
|
||||||
|
obj._reportEndTime = new Date().getTime();
|
||||||
|
reportCGI(obj.report, obj._reportStartTime, obj._reportEndTime, request);
|
||||||
|
}
|
||||||
|
|
||||||
if (obj.isLogin) {
|
if (obj.isLogin) {
|
||||||
// 登录请求
|
// 登录请求
|
||||||
var s = "";
|
var s = "";
|
||||||
@@ -222,12 +272,8 @@ function request(obj) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: function (res) {
|
fail: function (res) {
|
||||||
wx.showModal({
|
|
||||||
title: "请求失败",
|
|
||||||
content: res.errMsg,
|
|
||||||
showCancel: false
|
|
||||||
})
|
|
||||||
fail(obj, res);
|
fail(obj, res);
|
||||||
|
console.error(res);
|
||||||
},
|
},
|
||||||
complete: function () {
|
complete: function () {
|
||||||
obj.count --;
|
obj.count --;
|
||||||
@@ -244,15 +290,57 @@ function uploadFile(obj) {
|
|||||||
}
|
}
|
||||||
obj.formData[sessionName] = session;
|
obj.formData[sessionName] = session;
|
||||||
|
|
||||||
|
// 如果有全局参数,则添加
|
||||||
|
var gd = {};
|
||||||
|
if(typeof globalData == "function") {
|
||||||
|
gd = globalData();
|
||||||
|
} else if(typeof globalData == "object") {
|
||||||
|
gd = globalData;
|
||||||
|
}
|
||||||
|
obj.formData = Object.assign({}, gd, obj.formData);
|
||||||
|
|
||||||
obj.dataType = obj.dataType || 'json';
|
obj.dataType = obj.dataType || 'json';
|
||||||
|
|
||||||
|
// 如果请求的URL中不是http开头的,则自动添加配置中的前缀
|
||||||
|
var url = obj.url.startsWith('http') ? obj.url : (urlPerfix + obj.url);
|
||||||
|
|
||||||
|
// 在URL中自动加上登录态和全局参数
|
||||||
|
if(session) {
|
||||||
|
if(url.indexOf('?') >= 0) {
|
||||||
|
url += '&' + sessionName + '=' + session;
|
||||||
|
} else {
|
||||||
|
url += '?' + sessionName + '=' + session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有全局参数,则在URL中添加
|
||||||
|
for(var i in gd) {
|
||||||
|
if(url.indexOf('?') >= 0) {
|
||||||
|
url += '&' + i + '=' + gd[i];
|
||||||
|
} else {
|
||||||
|
url += '?' + i + '=' + gd[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有上报字段配置,则记录请求发出前的时间戳
|
||||||
|
if(obj.report) {
|
||||||
|
obj._reportStartTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
wx.uploadFile({
|
wx.uploadFile({
|
||||||
url: urlPerfix + obj.url,
|
url: url,
|
||||||
filePath: obj.filePath || '',
|
filePath: obj.filePath || '',
|
||||||
name: obj.name || '',
|
name: obj.name || '',
|
||||||
formData: obj.formData,
|
formData: obj.formData,
|
||||||
success: function (res) {
|
success: function (res) {
|
||||||
if (res.statusCode == 200 && res.errMsg == 'uploadFile:ok') {
|
if (res.statusCode == 200 && res.errMsg == 'uploadFile:ok') {
|
||||||
|
|
||||||
|
// 如果有上报字段配置,则记录请求返回后的时间戳,并进行上报
|
||||||
|
if(obj.report && typeof reportCGI == "function") {
|
||||||
|
obj.endTime = new Date().getTime();
|
||||||
|
reportCGI(obj.report, obj._reportStartTime, obj._reportEndTime, request);
|
||||||
|
}
|
||||||
|
|
||||||
if(obj.dataType == 'json') {
|
if(obj.dataType == 'json') {
|
||||||
try {
|
try {
|
||||||
res.data = JSON.parse(res.data);
|
res.data = JSON.parse(res.data);
|
||||||
@@ -284,12 +372,8 @@ function uploadFile(obj) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: function (res) {
|
fail: function (res) {
|
||||||
wx.showModal({
|
|
||||||
title: "请求失败",
|
|
||||||
content: res.errMsg,
|
|
||||||
showCancel: false
|
|
||||||
})
|
|
||||||
fail(obj, res);
|
fail(obj, res);
|
||||||
|
console.error(res);
|
||||||
},
|
},
|
||||||
complete: function () {
|
complete: function () {
|
||||||
obj.count --;
|
obj.count --;
|
||||||
@@ -321,8 +405,8 @@ function fail(obj, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: title || "操作失败",
|
title: title,
|
||||||
content: content || "服务器异常,请稍后重试",
|
content: content || "网络或服务异常,请稍后重试",
|
||||||
showCancel: false
|
showCancel: false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -355,13 +439,14 @@ function getCache(obj, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function login(callback) {
|
||||||
|
checkSession(callback, {})
|
||||||
|
}
|
||||||
|
|
||||||
function init(params) {
|
function init(params) {
|
||||||
sessionName = params.sessionName || 'session';
|
sessionName = params.sessionName || 'session';
|
||||||
loginTrigger = params.loginTrigger || function () { return false };
|
loginTrigger = params.loginTrigger || function () { return false };
|
||||||
codeToSession = Object.assign({}, {
|
codeToSession = params.codeToSession || {};
|
||||||
method: 'GET',
|
|
||||||
codeName: 'code'
|
|
||||||
}, params.codeToSession);
|
|
||||||
successTrigger = params.successTrigger || function () { return true };
|
successTrigger = params.successTrigger || function () { return true };
|
||||||
urlPerfix = params.urlPerfix || "";
|
urlPerfix = params.urlPerfix || "";
|
||||||
successData = params.successData || function (res) { return res };
|
successData = params.successData || function (res) { return res };
|
||||||
@@ -370,6 +455,9 @@ function init(params) {
|
|||||||
reLoginLimit = params.reLoginLimit || 3;
|
reLoginLimit = params.reLoginLimit || 3;
|
||||||
errorCallback = params.errorCallback || null;
|
errorCallback = params.errorCallback || null;
|
||||||
sessionIsFresh = params.doNotCheckSession || false;
|
sessionIsFresh = params.doNotCheckSession || false;
|
||||||
|
reportCGI = params.reportCGI || false;
|
||||||
|
mockJson = params.mockJson || false;
|
||||||
|
globalData = params.globalData || false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
session = wx.getStorageSync(sessionName) || '';
|
session = wx.getStorageSync(sessionName) || '';
|
||||||
@@ -378,11 +466,16 @@ function init(params) {
|
|||||||
|
|
||||||
function requestWrapper(obj) {
|
function requestWrapper(obj) {
|
||||||
obj = preDo(obj);
|
obj = preDo(obj);
|
||||||
|
if(mockJson && mockJson[obj.url]) {
|
||||||
|
// mock 模式
|
||||||
|
mock(obj);
|
||||||
|
} else {
|
||||||
getCache(obj, function() {
|
getCache(obj, function() {
|
||||||
checkSession(function () {
|
checkSession(function () {
|
||||||
request(obj);
|
request(obj);
|
||||||
}, obj)}
|
}, obj)}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadFileWrapper(obj) {
|
function uploadFileWrapper(obj) {
|
||||||
@@ -397,9 +490,23 @@ function setSession(s) {
|
|||||||
sessionIsFresh = true;
|
sessionIsFresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mock(obj) {
|
||||||
|
var res = {
|
||||||
|
data: mockJson[obj.url]
|
||||||
|
};
|
||||||
|
if (successTrigger(res.data) && typeof obj.success == "function") {
|
||||||
|
// 接口返回成功码
|
||||||
|
obj.success(successData(res.data));
|
||||||
|
} else {
|
||||||
|
// 接口返回失败码
|
||||||
|
fail(obj, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init: init,
|
init: init,
|
||||||
request: requestWrapper,
|
request: requestWrapper,
|
||||||
uploadFile: uploadFileWrapper,
|
uploadFile: uploadFileWrapper,
|
||||||
setSession: setSession
|
setSession: setSession,
|
||||||
|
login: login
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user