Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add controller #209

Merged
merged 4 commits into from
Jan 10, 2017
Merged

docs: add controller #209

merged 4 commits into from
Jan 10, 2017

Conversation

dead-horse
Copy link
Member

No description provided.


1. 获取用户通过 http 传递过来的请求参数。
1. 校验、组装参数。
1. 调用 service 进行业务处理,必要时处理转换 service 的返回,让它适应用户的需要。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

必要时处理转换 service 的返回

必要时处理转换 service 的返回结果


## 如何编写 controller

所有的 controller 都必须放置于 `app/controller` 目录下,每一个 controller 都是一个 generator function,它的 `this` 都被绑定成了 [Context](./extend.md#context) 对象的实例,通过它我们可以拿到框架给我们封装的各种便捷属性和方法。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

都必须放置于

都必须放在

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

都被绑定成了 Context 对象的实例

都被绑定成了 Context 的实例

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通过它我们可以拿到框架给我们封装的各种便捷属性和方法。

通过它我们可以拿到框架封装好的各种便捷属性和方法。


所有的 controller 都必须放置于 `app/controller` 目录下,每一个 controller 都是一个 generator function,它的 `this` 都被绑定成了 [Context](./extend.md#context) 对象的实例,通过它我们可以拿到框架给我们封装的各种便捷属性和方法。

例如我们写一个对应到 `POST /api/posts` 接口的 controller,我们会在 `app/controller` 目录下创建一个 post.js 文件
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post.js 文件

post.js 文件

文件名需要加上代码块

};
exports.create = function* () {
// 校验参数
this.validate(createRule);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate 突然间引入,是否可以提示一下,下文中会详细解释 validate

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

后面有些

this.validate(createRule);
// 组装参数
const author = this.session.userId;
const create = Object.assign(this.request.body, { author });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create 是什么?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

都改成 req

// 校验参数
this.validate(createRule);
// 组装参数
const author = this.session.userId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userId ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里暂时不直接引入 userId 吧,通过这个引入 session 的概念


在上面的例子中我们引入了许多新的概念,但还是比较直观,容易理解的,我们会在下面对它们进行更详细的介绍。

## http 基础
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

http 这个专有名词是否都全大写? HTTP


由于 controller 基本上是业务开发中唯一和 http 协议打交道的地方,在继续往下了解之前,我们首先简单的看一下 http 协议是怎样的。

如果我们发起一个请求请求前面例子中提到的 controller,我们发起的 http 请求的内容就会是下面这样的
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果我们发起一个请求请求前面例子中提到的 controller,我们发起的 http 请求的内容就会是下面这样的

如果我们发起一个 HTTP 请求到前面例子中提到的 controller,那么 HTTP 请求的内容会类似是下面这样的:

@dead-horse dead-horse removed the WIP label Jan 10, 2017
@codecov-io
Copy link

codecov-io commented Jan 10, 2017

Current coverage is 97.48% (diff: 100%)

Merging #209 into master will decrease coverage by 0.26%

@@             master       #209   diff @@
==========================================
  Files            34         35     +1   
  Lines           891       1034   +143   
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
+ Hits            871       1008   +137   
- Misses           20         26     +6   
  Partials          0          0          

Powered by Codecov. Last update 98506f0...6a24575

@dead-horse
Copy link
Member Author

可以 review 了

@popomore popomore mentioned this pull request Jan 10, 2017
31 tasks
@@ -0,0 +1,660 @@
title: Controller
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

controller


## 什么是 controller

前面章节写到,我们通过 router 将用户的请求基于 method 和 url 分发到了对应的 controller 上,那 controller 负责做什么?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[router](./router.md)


- 在 [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) 接口中,controller 接受用户的参数,从数据库中查找内容返回给用户或者将用户的请求更新到数据库中。
- 在 html 页面请求中,controller 根据用户访问不同的 url,渲染不同的模板得到 html 返回给用户。
- 在代理服务器中,controller 将用户的请求转发到其他服务器上,并将其他服务器的返回响应给用户。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

并将其他服务器的返回响应给用户。

并将转发结果返回给用户。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

并将其他服务器的处理结果返回给用户。

- 在 html 页面请求中,controller 根据用户访问不同的 url,渲染不同的模板得到 html 返回给用户。
- 在代理服务器中,controller 将用户的请求转发到其他服务器上,并将其他服务器的返回响应给用户。

框架推荐 controller 层主要处理用户请求参数(校验、转换),调用对应的 [service](./service.md) 方法处理业务,并封装业务返回结果:
Copy link
Contributor

@leoner leoner Jan 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

框架推荐 controller 层主要对用户的请求参数进行处理(校验、转换),然后调用对应的 service 方法处理业务,得到业务结果后封装并返回:

感觉好像这样通顺点, 就是 校验、转换 应该是处理的方式, 感觉应该放到处理后面。


由于 controller 基本上是业务开发中唯一和 HTTP 协议打交道的地方,在继续往下了解之前,我们首先简单的看一下 HTTP 协议是怎样的。

如果我们发起一个请求请求前面例子中提到的 controller,我们发起的 HTTP 请求的内容就会是下面这样的
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉一个请求, 也能理解, 2个请求感觉有点绕了。


exports.listApp = function*() {
assert.equal(this.params.projectId, '1');
assert.equal(this.params.appId, '2');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

要写参数值都是字符串类型么?


虽然我们可以通过 url 传递参数,但是还是有诸多限制

- 浏览器中会对 url 的长度有所限制,如果需要传递的参数过多就会无法传递。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

长度限制的说明 url 加上外链


{"title": "controller", "content": "what is controller"}
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curl -X POST http://127.0.0.1:7001/api/posts --data '{"title":"controller", "content": "what is controller"}' --header 'Content-Type:application/json'

是不是这里给配备一个 curl 的请求说明,可以让他更好的测试和理解?

- 上传文件必须在其他 field 之前。
- 只支持上传一个文件。

如果要获取同时上传的多个文件,不能通过 `this.getFileStream()` 来获取
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉这句话没写完。。。

console.log('mime: ' + part.mime);
// 文件处理,上传到云存储等等
const result = yield this.oss.put('egg-multipart-test/' + part.filename, part);
console.log(result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```js
module.exports = {
multipart: {
whitelist: [ '.png '], // 覆盖整个白名单,只允许上传 '.png' 格式
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

多了一个空格


### header

除了从 URL 和请求 body 上获取参数之外,还有许多参数是通过请求 header 传递的。框架提供了一些辅助属性和方法来获取。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

都大写 URL 吧

- `context.headers`,`context.header`,`context.request.headers`,`context.request.header`:这几个方法是等价的,都是获取整个 header 对象。
- `context.get(name)`,`context.request.get(name)`:获取请求 header 中的一个字段的值,如果这个字段不存在,会返回空字符串。

由于 header 比较特殊,有一些是 `HTTP` 协议规定了具体含义的(例如 `Content-Type`,`Accept`),有些是反向代理设置的,已经约定俗成(X-Forwarded-For),框架也会对他们增加一些便捷的 getter,详细的 getter 可以查看 [API]() 文档。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


#### `context.ips`

通过 `context.ips` 获取请求经过设备的所有 ip 地址列表,通过读取 `config.ipHeaders` 中配置的 header 的值,获取不到时为空数组。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认值

- sign(Boolean):设置是否对 cookie 进行签名,如果设置为 true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为 true。
- encrypt(Boolean):设置是否对 cookie 进行加密,如果设置为 true,则在发送 cookie 前会对这个键值对的值进行加密,客户端无法读取到 cookie 的值。默认为 false。

在设置 cookie 时我们需要思考清楚这个 cookie 的作用,它需要被浏览器保存多久?是否可以被 js 获取到?是否可以被前端修改?默认的配置下设置的 cookie 前端可以看到,js 不能访问,不能被客户端(手工)篡改。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认的配置下设置的 cookie 前端可以看到,js 不能访问,不能被客户端(手工)篡改。 加粗


由于我们在 cookie 中需要用到加解密和验签,所以需要配置一个秘钥供加密使用。在 `config/config.default.js` 中

```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

js


```js
module.exports = {
key: 'koa:sess', // 承载 session 的 cookie 键值对名字
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个好像不对


```js
exports.create = function*() {
const errors = this.app.validator.validate(createRule, this.request.body);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try catch


### 校验规则

参数校验通过 [parameter](https://github.com/node-modules/parameter#rule) 完成,支持的校验规则可以在文档中查阅到。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

文档中

该文档中


service 的具体写法,请查看 [service](./service.md) 章节。

## 发送 http 响应
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP


#### 渲染模板

通常来说,我们不会手写 html 页面,而是会通过模板引擎进行生成。egg 自身没有集成任何一个模板引擎,但是约定了[view 插件的规范](../practice/view.md),通过接入的模板引擎,可以直接使用 `this.render(template)` 来渲染模板生成 html。具体示例可以查看 quick start 中的 [模板渲染](../guide/quickstart.md#模板渲染) 部分。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

egg => 框架

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里故意写成 egg 的,因为上层的框架一般都会封装一个 view 插件的


通常来说,我们不会手写 html 页面,而是会通过模板引擎进行生成。egg 自身没有集成任何一个模板引擎,但是约定了[view 插件的规范](../practice/view.md),通过接入的模板引擎,可以直接使用 `this.render(template)` 来渲染模板生成 html。具体示例可以查看 quick start 中的 [模板渲染](../guide/quickstart.md#模板渲染) 部分。

#### jsonp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSONP


#### jsonp

有时我们需要给非本域的页面提供接口服务,又由于一些历史原因无法通过 [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) 实现,可以通过 [jsonp](https://en.wikipedia.org/wiki/JSONP) 来进行响应。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JSONP

Copy link
Member

@fengmk2 fengmk2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@fengmk2 fengmk2 merged commit 85ebdbd into master Jan 10, 2017
@fengmk2 fengmk2 deleted the docs-controller branch January 10, 2017 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants