微信小程序使用formdata请求大坑! + 键盘吸附效果 + 常见代码

601 阅读5分钟

最近菜鸟又来开发微信小程序了,感觉只要一段时间不搞微信小程序,再来搞必出问题,且代码不熟练,一些封装的东西都要去别的项目里面找,所以这里菜鸟直接总结一下,方便后续开发微信小程序!

常见代码

这里菜鸟暂时只总结了网络请求的封装,因为菜鸟开发的微信小程序都不是很难,基本上只有2-3个页面,只是完成部分简单工作而已!

后续如果开发更难的微信小程序,菜鸟会回来这里补充。

网络请求封装

request.js

const BASE_URL = 'http://172.16.40.26:8085'
const myrequest = (obj) => {
  wx.showLoading({
    mask: true,
    title: '加载中...',
  })
  return new Promise((resolve, reject) => {
    wx.request({
      url: BASE_URL + obj.url,
      data: obj.data ? obj.data : null,
      header: obj.header ? obj.header : {'content-type': 'application/json'},
      method: obj.method ? obj.method : "GET",
      responseType: obj.responseType ? obj.responseType : '',
      success: (result) => {
        console.log(result)
        if (result.statusCode == 200) {
          resolve(result.data);
        } else {
          reject(result.errMsg)
        }
      },
      fail: (err) => {
        reject("服务器连接异常,请检查网络再试");
      },
      complete: ()=> {
        wx.hideLoading();
      }
    })
  })
}

module.exports = {
  myrequest,
}

使用

const {myrequest}  = require("./request.js")

function loginApi(params) {
  return myrequest({
    url: '/login',
    method: 'POST',
    data: params
  })
}

module.exports = {
  loginApi,
}

封装的loginApi使用

const { loginApi } = require("../../network/api.js")

Page({
  data: {
    contractNum: ''
    ……
  }
})

自定义导航栏

这里菜鸟已经写过了,直接参考:微信小程序 自定义导航栏

实现键盘吸附效果

登录界面代码,这里主要看 重点代码 就行,不好单独提出来,所以就整个搬过来了,希望各位读者可以接受!

login.wxml

<!--pages/login/login.wxml-->
<view
  class="navtitleBox"
  style="padding-top:{{headerHeight}}px"
>
  <view class="title">
    <text>XXXXlims系统</text>
  </view>
  <image class="loginBg" src="../../imgs/loginBg.png" mode="widthFix"></image>
  
  <!-- 重点代码 -->
  <view class="loginForm" style="bottom: {{formposition}}rpx">
    <view class="formTitle">
      <text>欢迎登录</text>
    </view>
    <view class="formView">
      <form catchsubmit="formSubmit">
        <view class="page-section">
          <view class="page-section-title">用户名:</view>
          <input class="weui-input" bindkeyboardheightchange="focusFun" bindblur="getUsernameFun" placeholder="请输入用户名" />
        </view>

        <view class="page-section">
          <view class="page-section-title">密码:</view>
          <input class="weui-input" password bindkeyboardheightchange="focusFun" bindblur="getPasswordFun" placeholder="请输入密码" />
        </view>

        <view class="btn-area">
          <button type="primary" formType="submit">登录</button>
        </view>
      </form>
    </view>
  </view>
</view>

login.wxss

/* pages/login/login.wxss */
page {
  height: 100vh;
  overflow: hidden;
}
.navtitleBox {
  background-color: #3f8cff;
  height: 100%;
}
.title {
  text-align: center;
  transform: translateY(-50%);
  color: #fff;
}
.loginBg {
  width: 100%;
}

// 重点代码
.loginForm {
  width: 100%;
  position: absolute;
  background-color: #3f8cff;
}

.formTitle {
  color: #fff;
  font-size: 50rpx;
  text-align: center;
  margin-top: 80rpx;
  margin-bottom: 50rpx;
}
.formView {
  box-sizing: border-box;
  background-color: #fff;
  width: 85%;
  margin: auto;
  border-radius: 20rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 50rpx;
}
.page-section {
  display: flex;
  align-items: center;
  line-height: 80rpx;
  margin: 30rpx;
}
.page-section-title {
  width: 150rpx;
  text-align: center;
}
.weui-input {
  width: calc(100% - 150rpx);
  border-bottom: #000 2rpx solid;
}
.btn-area {
  margin: 60rpx 0 30rpx;
}

login.js

import {loginApi} from '../../network/api'
const app = getApp()

Page({
  data: {
    headerHeight: app.globalData.headerHeight,
    formposition: 260,
    username: null,
    password: null,
  },
  
  // 重点代码  --》 有点bug,就是点击回车缩起来可以,但是点击那个键盘右上方的下箭头缩起来的时候就有问题
  focusFun(e) {
    this.data.formposition = 260
    this.setData({
      formposition: e.detail.height === 0 ? 260 : this.data.formposition + e.detail.height
    })
  },
  
  getUsernameFun(e) {
    this.data.username = e.detail.value
  },
  getPasswordFun(e) {
    this.data.password = e.detail.value
  },
  async formSubmit() {
    let res  = await loginApi(this.data.username,this.data.password)
    if(res.status === 200) {
      app.globalData.userInfo = res
      return
    }
    wx.showToast({
      title: res,
      icon: "none",
      duration: 1000
    })
  },
})

微信小程序 使用formdata请求大坑

菜鸟做这个登录的时候,发现后端接收的不是 json 对象格式,而是 formdata 格式,一问才知道是后端使用的框架搞成这样的,那没办法,后端不好改,就只能前端扛下所有了!

(建议还是后端改,直接怼回去,狗头保命!)

然后菜鸟在微信小程序社区一搜,果然不是菜鸟一个人遇见了,而且也真的有解决办法,这里感谢该文章:使用wx.request发送multipart/form-data请求的方法

菜鸟下面的就是直接取自该文章!

如果 wx.request 中仅指定 'content-type' 为 'multipart/form-data',服务端会报"no multipart boundary was found"的错误,就像这个帖子里描述的:developers.weixin.qq.com/community/d…

尽管指定了 content-type 为 'mutipart/form-data' ,但是 wx.request 并不会为我们自动添加 boundary,既然如此,我们自己加不就可以了吗?经过测试,确认了这个方法可行,前端示例代码如下:

wx.request({
      url:'http://localhost:8080/test/multipart-form',
      method:'POST',
      header: {
        'content-type':'multipart/form-data; boundary=XXX'
      },
      data:'\r\n--XXX' +
        '\r\nContent-Disposition: form-data; name="field1"' +
        '\r\n' +
        '\r\nvalue1' +
        '\r\n--XXX' +
        '\r\nContent-Disposition: form-data; name="field2"' +
        '\r\n' +
        '\r\nvalue2' +
        '\r\n--XXX--'
    })

这里,我向服务端传递了两个参数:field1=value1, field2=value2!

注意

这里必须按照这个格式来,单双引号都不能变,菜鸟就是自己打了一次,用的双引号包裹的单引号,结果 formdata 中就获取不到值了!

菜鸟的代码

api.js

import {myrequest} from './request'

function loginApi(username,password) {
  return myrequest({
    url: '/login',
    method: 'POST',
    header: {'content-type': 'multipart/form-data; boundary=XXX'},
    data: '\r\n--XXX' +
    '\r\nContent-Disposition: form-data; name="username"' +
    '\r\n' +
    '\r\n'+ username +
    '\r\n--XXX' +
    '\r\nContent-Disposition: form-data; name="password"' +
    '\r\n' +
    '\r\n' + password +
    '\r\n--XXX--'
  })
}

module.exports = {
  loginApi,
}

结合上面的 login.js 看,前端传递过去的值正确

在这里插入图片描述

微信小程序每次request请求,Cookie不一样?

这次做微信小程序,发现和后台建立连接,每次都会新建一个连接,这样就无法在同一个连接上进行操作,那么后台中的数据,后台就无法通过缓存进行传输,所以必须得解决这个问题。

解决办法

//保存cookies,解决request每次请求连接不一样的bug
const phpsessidarr = result.cookies[0].split(";"); //这里result是后台第一返回的,可以从中获取到cookies
const phpsessid = phpsessidarr[0];
const header = {'content-type': 'application/json', 'Cookie': phpsessid};
wx.request({
      url: common_urlapi+url,
      data:{},
      header: header,
      method:"POST",
      success:res=>{},
      fail:err=>{}
)}

其它更多参数设置:

Header:请求头参数详解

注意:

菜鸟最近在公司开发微信小程序,发现并没有发现这个问题,一问才知道,原来是因为之前大学做这个项目的时候,老王保存了会话信息,所以cookie是老王设置并返回,后面又要通过cookie获取东西的,所以才会有上面每次建立新连接导致cookie不一样的情况出现!

后端分析的原因:

我和前端小程序交互,由于微信小程序的内部原因,每一次与我后端建立会话后,微信小程序并没有维持这段会话,而是每一次请求都是一个新的会话,这就导致不能正常维持前后端交互流程。后来经过分析,微信小程序在http请求头cookie加上我后端发过来的session_id就可以了,这一点和浏览器不一样,浏览器会默认保存session_id,每次请求都会带上上一次的session_id维持会话。

详见:回首2020,展望2021