---
title: "在微信小程序中使用FeathersJS的RESTful API"
date: 2018-12-28T18:29:40.000Z
author: Z.SHINCHVEN
tags: [微信小程序, FeathersJS, FeathersJS client, HTTP, RESTful, CRUD]
canonical: https://atlassc.net/2018/12/29/use-feathersjs-restful-api-in-wechat-miniprogram
---
## 前言

最近在做微信小程序开发，为已有的一个Web应用程序提供微信小程序客户端。这个Web应用程序基于[FeathersJS](https://feathersjs.com/)
开发，提供[RESTful](https://zh.wikipedia.org/wiki/%E8%A1%A8%E7%8E%B0%E5%B1%82%E7%8A%B6%E6%80%81%E8%BD%AC%E6%8D%A2)
API，因此也想在小程序共用大部分API。

## 微信小程序中的HTTP请求

微信小程序开发中使用[wx.request(Object object)](https://developers.weixin.qq.com/miniprogram/dev/api/wx.request.html)
这个API进行http数据请求，且仅支持https证书加密访问。

## JWT认证

微信小程序的容器并不是一个标准的浏览器，在使用*wx.request*
这个api进行数据请求时，并不会自动带上cookie、session等信息，因此需要自行管理认证信息。我们的应用程序使用的认证方式是[jwt](https://jwt.io/)
，要实现jwt认证只需要在发送http请求时将token放于header中即可，这和Android、iOS端的http请求框架封装没有什么两样。

## CRUD

### 请求方法对照

参考维基百科中对[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
的描述，我制作了这样一张表来对照微信小程序中http请求方法与RESTful API中的接收请求方法。

| Operation       | SQL    | HTTP               | RESTful WS | DDS         | FeathersJS REST Client                                                                                                               |
|-----------------|--------|--------------------|------------|-------------|--------------------------------------------------------------------------------------------------------------------------------------|
| Create          | INSERT | PUT / POST         | POST       | WRITE       | [create](https://docs.feathersjs.com/api/client/rest.html#create)                                                                    |
| Read(Retrieve)  | SELECT | GET                | GET        | read / take | [get](https://docs.feathersjs.com/api/client/rest.html#get) / [find](https://docs.feathersjs.com/api/client/rest.html#find)          |
| Update(Modify)  | UPDATE | PUT / POST / PATCH | PUT        | write       | [update](https://docs.feathersjs.com/api/client/rest.html#update) / [patch](https://docs.feathersjs.com/api/client/rest.html#patch)  |
| Delete(Destroy) | DELETE | DELETE             | DELETE     | dispose     | [remove](https://docs.feathersjs.com/api/client/rest.html#remove)                                                                    |

根据我的实际情况，其中*HTTP*列是微信小程序端的请求方法（*method*），*FeathersJS RESTclient*列为FeathersJS server api
中的接收请求方法。

### 微信小程序没有PATCH

微信小程序的*wx.request*不支持*PATCH*和*FeathersJS*中的*update*两种请求方式，因此我们只能使用功能类似的PUT来完成数据修改。

而这是为什么呢？我在寻找解决方案的过程中，我查到了以下这些文献，也许能解释为什么微信团队会选择禁用或者不实现PATCH方法：

根据维基百科中对[PATCH](https://en.wikipedia.org/wiki/Patch_verb)的描述：

- The PATCH method is a request method supported by the HTTP protocol for making partial changes to an existing
  resource.
- PATCH方法是HTTP协议支持的请求方法，用于对现有资源进行部分更改。

而[spring.io 关于的REST 的文档](https://spring.io/understanding/REST#patch)中提到：

- Update only the specified fields of an entity at a URI. **A PATCH request is neither safe nor idempotent (RFC 5789).**
  That's because a PATCH operation cannot ensure the entire resource has been updated.
- 仅更新URI上实体的指定字段。 **PATCH请求既不安全也不是幂等（RFC 5789）。** 这是因为PATCH操作无法确保整个资源已更新。

### 转发PUT到PATCH

FeathersJS中使用基于[Sequelize](http://docs.sequelizejs.com/)
所创建的Service，无论是[update](https://docs.feathersjs.com/api/client/rest.html#update)
还是[patch](https://docs.feathersjs.com/api/client/rest.html#patch)
都支持仅更新部分提交的字段，未提交的字段会被忽略。而我们项目中使用的是基于knex的Service，如果在小程序上调用PUT且不传全属性，则会将没有传的属性会当作null更新进数据库，如果在其他客户端调用UPDATE且不传全属性，则会返回400请求体错误。

为了能够支持部分属性更改，我在FeathersJS app启动时添加了一个简单的middleware，将api路由上所有的UPDATE和PUT求请改成了PATCH：

```JavaScript
app.use('/api/*', function (req, resp, next) {
  if (req.method.toUpperCase() === "PUT" || req.method.toUpperCase() === "UPDATE") {
    req.method = 'PATCH';
  }
  next();
});
```
