Quantcast
Channel: CNode:Node.js专业中文社区
Viewing all 14821 articles
Browse latest View live

开发工程师-APICloud-坐标北京

$
0
0

岗位职责: 薪资待遇:15K-25K 1、APICloud Atom&VSCode开发工具的架构设计和研发工作; 2、每周版本版本升级和发布工作; 3、开发过程中设计、编码及相关文档编写,解决开发中的技术问题, 对其质量、性能负责。 任职要求: 1、精通Javascript语言,有良好的编码风格,熟悉ECMAScript规范和技术; 2、熟悉vscode或者atom编码工具的使用,并了解其运行原理; 3、良好的沟通能力,计算机相关专业本科及以上学历; 4、对Html5及周边技术感兴趣,学习能力强; 5、有发布过vscode或者atom插件者优先; 6、熟悉MAC、Windows、Linux操作系统使用者优先。 工作地址 北京市海淀区龙翔路甲1号泰翔商务楼五层507、508室 联系人:王曼 15010775436


vue +vue-socket 实现的一个聊天室项目

$
0
0

loopback-chat

这是一个运用前端框架VueJS,UI框架Iview的博客项目,后端使用Node框架LoopBack。(一开始打算写个blog,后来觉得还是写案例比较好,所以项目名称会有些奇怪)

演示

线上地址

DEMO

技术栈

功能列表

  • 登录
  • 注册
  • 根据姓名生成随机头像
  • 聊天
  • 添加好友
  • 实时消息通知
  • 根据好友昵称 分组 好友列表
  • 登出

项目简介

项目使用了socket.io,vue,docker,loopback,iview,不要问我为什么使用这些,因为这是我公司现在的技术栈,所以自己就做一些项目来练手,把公司的技术栈走通。因为自己以前是写AngularJS的,因为某些原因又开始用NodeJS 开发后端,现在在公司是专职后端开发,但是就是爱折腾,不舍得放弃前端。下面写一些这个感受(不喜勿喷)

vueJS vs Angular(1.xx)

我这里主要写的是angular1.xx的,因为是在实习期写的angular+gulp,如果有不对的地方可以指出(也许有些过时)。

  • 相似之处(方便理解)
    • angular的service 和 vue 中的vuex store 很像,都可以用来保存状态
    • store 的dispatch 和 angular 的 $broadcast emit 作用类似,但是有不同。比如说父子组件通信
    • vue 中每个components 中的this 指针 和angular 中的$scope 差不多,都是当前页面下一些变量
    • filter 的用法相类似
  • 不同之处
    • 我们习惯在angularJS中把所有方法都放在controller 中,无论是watch,页面生命周期的一些监听,都在controller里,但是在vueJS,把页面的变量定义都分开,分开成不同方法中,不知道我是不是因为后端开发,所以更喜欢angularJS 把controller service,router 都分开定义,把页面的业务(方法)都写在controller中,然后依赖注入(写过一段java,喜欢这种方式吧)。
    • angular 定义我更多的觉得它是从module开始的,每个module下面从router,controller,service,template,但是vueJS 让我更多觉得它是从components开始的,每个组件来组装成一个template。(理解不到位,可能写的不对)
    • angular 的双向绑定的脏值检测和双向绑定和vuejs 的单向数据流就省略了,网上说了很多了。

踩坑的几点

  • socket + redis
    • 以前一直很傻的以为socket +redis ,其实是吧socketId 放在redis 里,然后可以实现多线程通信,后来查了很久,才发现,socket.io只是利用的redis pub-sub 的服务,socket.id是不存在redis 里的!!!
    • vue 中this.$router 和this.$route 的区别,那天写代码,找个很久,关键还是自己不细心,路由传参一直拿不到,感觉很奇怪,后来才发现两个不是一个东西
    • vue 有个插件集成socket.io,叫vue-socket,但是我用的时候发现一个问题就是后端如果emit,如果想要dispatch,不能写成像文档一样,例如
      后端		socket.to(messageModel.chatRoomId).emit('message', messageModel);
      	前端的store actions 监听  
      	文档写法
      	actions: {
      	 socket_Message: (context, message) => {},
      	}
      	正确写法
      	actions: {
      	 socket_socketMessage: (context, message) => {},
      	}
      

项目缺点

  • css 写的很乱,本人css很烂,后期会重新整理一遍
  • 变量定义随意(后期重构的时候会考虑改一下)

结尾

还是那句话,如果有错的地方,欢迎大家指正,毕竟本人比较菜,毕竟写这么多是欢迎大家指出我的错误,能够成长,如果有同学不懂的地方,也欢迎提问,issue也行,当然想关注下去,也可以star 一下或者watch

React 16.3来了:带着全新的Context API

$
0
0

文章概览

React在版本16.3-alpha里引入了新的Context API,社区一片期待之声。我们先通过简单的例子,看下新的Context API长啥样,然后再简单探讨下新的API的意义。

文中的完整代码示例可在笔者的GitHub上找到,点击传送门

看下新的Context API

需要安装16.3-alpha版本的react。构建步骤非本文重点,可参考笔者GitHub上的demo

npm install react@next react-dom@next

下面,直接来看代码,如果用过react-redux应该会觉得很眼熟。

首先,创建context实例:

import React from 'react';
import ReactDOM from 'react-dom';

// 创建context实例
const ThemeContext = React.createContext({
  background: 'red',
  color: 'white'
});

然后,定义App组件,注意这里用到了Provider组件,类似react-reduxProvider组件。

class App extends React.Component {

  render () {
    return (
      <ThemeContext.Provider value={{background: 'green', color: 'white'}}>
        <Header />
       </ThemeContext.Provider>
    );
  }
}

接下来,定义HeaderTitle组件。注意:

  1. Title组件用到了Consumer组件,表示要消费Provider传递的数据。
  2. Title组件是App组件,但跳过了Header消费数据。
class Header extends React.Component {
  render () {
    return (
      <Title>Hello React Context API</Title>
    );
  }
}

class Title extends React.Component {
  render () {
    return (
      <ThemeContext.Consumer>
        {context => (
          <h1 style={{background: context.background, color: context.color}}>
            {this.props.children}
          </h1>
        )}
      </ThemeContext.Consumer>
    );
  }
}

最后,常规操作

ReactDOM.render(
  <App />, 
  document.getElementById('container')
);

看下程序运行结果:

为什么有新的Context API

用过redux + react-redux的同学,应该会觉得新的Context API很眼熟。而有看过react-redux源码的同学就知道,react-redux本身就是基于旧版本的Context API实现的。

既然已经有了现成的解决方案,为什么还会有新的Context API呢?

  1. 现有Context API的实现存在一定问题:比如当父组件的shouldComponentUpdate性能优化,可能会导致消费了context数据的子组件不更新。
  2. 降低复杂度:类似redux全家桶这样的解决方案,给项目引入了一定的复杂度,尤其是对方案了解不足的同学,遇到问题可能一筹莫展。新Context API的引入,一定程度上可以减少不少项目对redux全家桶的依赖。

写在后面

新的Context API,个人对于性能上的提升更加期待些。至于降低复杂度、取代redux之类的,不是我关注的重点。下一步的计划就是多构造点用例来进行对比测试。

相关链接

本文完整代码示例

React新的Context API的RFC

架构师-坐标北京-APICloud

$
0
0

工作职责 薪资:15K-25K

  1. 根据业务发展需要,进行服务的技术方案选型、技术架构设计。
  2. 制定技术规范和操作流程,保障服务在高并发环境下的性能和稳定性。
  3. 研发基础的服务、开发标准代码框架和代码库,提升业务团队的开发效率和开发质量量。 职位要求
  4. 5年以上开发工作经验,3年以上架构设计经验;
  5. 在APP与服务器交互、面向服务架构方面有深刻理解与实际经验,具备指导开发人员优化代码的能力;
  6. 熟练应用MySQL,具备优秀SQL优化能力,能够根据实际业务需求对数据库进行分库、分表、分区;
  7. 熟悉kafka、Zookeeper等流行的分布式系统及其架构;
  8. 熟悉solr、lucene等一种或多种搜索应用服务的使用;
  9. 有大型分布式系统的分析/设计/架构的经验,精通系统分层/分割原则。能以微服务思想进行系统架构设计; 7.有大数据集群、分布式系统相关经验者优先考虑
  10. 熟悉node.js开发语言者优先考虑。

工作地址 北京市海淀区龙翔路甲1号泰翔商务楼五层507、508室 联系人:王曼 15010775436

egg里怎么完美使用sequelize

$
0
0

感觉model层写的很混乱,求一个example

module.exports = app => {
  const { DATE, INTEGER, STRING } = app.Sequelize;

  return app.model.define('Post', {
    title: STRING,
    user_id: INTEGER,
    created_at: DATE,
    updated_at: DATE,
  }, {
    classMethods: {
      associate() {
        app.model.Post.belongsTo(app.model.User, { as: 'user' });
      },
    },
  });
};

这种写法,真是写不下去 能否有办法变成类似于这样

Class Post extends Sequelize {
		static ...
}

nodejs开发接口自动化02-处理cookie问题

$
0
0

本教程使用的到技术栈如下: 操作系统:windows10, 编程语言:node.js 8.9.4 https://nodejs.org/en/代码编辑器: CukeTest http://cuketest.com/用到的库 got :https://www.npmjs.com/package/got cooike : https://www.npmjs.com/package/cookie

cookie 简介

这里引自维基百科的说明 https://zh.wikipedia.org/wiki/Cookie

Cookie(复数形态Cookies),中文名称为“小型文本文件”或“小甜饼”[1],指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。网景公司的前雇员卢·蒙特利在1993年3月的发明[2]。最初定义于 RFC 2109。目前使用最广泛的 Cookie标准却不是 RFC 中定义的任何一个,而是在网景公司制定的标准上进行扩展后的产物。

Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie。 内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。

因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两瓶饮料。最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么,所以Cookie就是用来绕开HTTP的无状态性的“额外手段”之一。服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。

在刚才的购物场景中,当用户选购了第一项商品,服务器在向用户发送网页的同时,还发送了一段Cookie,记录着那项商品的信息。当用户访问另一个页面,浏览器会把Cookie发送给服务器,于是服务器知道他之前选购了什么。用户继续选购饮料,服务器就在原来那段Cookie里追加新的商品信息。结帐时,服务器读取发送来的Cookie就行了。

Cookie另一个典型的应用是当登录一个网站时,网站往往会请求用户输入用户名和密码,并且用户可以勾选“下次自动登录”。如果勾选了,那么下次访问同一网站时,用户会发现没输入用户名和密码就已经登录了。这正是因为前一次登录时,服务器发送了包含登录凭据(用户名加密码的某种加密形式)的Cookie到用户的硬盘上。第二次登录时,如果该Cookie尚未到期,浏览器会发送该Cookie,服务器验证凭据,于是不必输入用户名和密码就让用户登录了。

举例说明cookie的应用场景

大家熟悉的百度,如果我们在百度上登录过用户,当把浏览器关闭再次打开浏览器导航到百度的时候就会看到我们的账户自动登录,原理就是浏览器里存储的有cookie, 具体查看cookie的方式为: 打开chrome浏览器,url前面的安全可以看到
image.png点击cookie 可以看到具体的cookie信息 image.png如果讲这些cookie 都删除掉,点击删除按钮,那么我们再次打开百度首页我们看到的页面将会是未登录个人用户的页面。

使用got 库模拟 get请求

以百度为例,如果打开百度为用户未登录状态,那么我们看到的页面将是这样的 image.png先用代码 模拟未登录用户的时候,操作步骤如下:

let got = require('got')

let url = "http://www.baidu.com"

got.get(url).then(function(result){
    console.log(result.body)
})

CukeTest中将代码界面最大化,可以点击 运行脚本按钮 ,运行完成直接看到结果输出 image.png

CukeTest输出界面中可以看到 百度网页的源代码 image.png

在CukeTest中新建一个html文件,并将上一步打印出来的结果复制到html文件中–保存,在html文件上右键 可以在浏览器中打开,也可以用报表打开。 image.png我们可以看到 没有cookie 的时候 百度的未登录页面信息。

  • 编写带有cookie的代码我们事先打开浏览器导航到百度页面登录自己的百度账号,检查cookie,将cookie信息复制出来添加到如下代码 image.png
let got = require('got')
let cookie = require('cookie')

let option={
    headers:{
        cookie:[
            cookie.serialize('BAIDUID', 'B4F438F72D1CA0468D67EF98A20D3BA2:FG=1'),
            cookie.serialize('BDUSS', 'UFzYlctWERjckZRdEJPQ1gwOX5yNmlFbTBEbWhxb2s3MkJrdHAtVkxiODFQNk5hQVFBQUFBJCQAAAAAAAAAAAEAAAAXv9JNy6vX02ltenp5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADWye1o1sntaS'),
            cookie.serialize('BIDUPSID', 'B4F438F72D1CA0468D67EF98A20D3BA2'),
            cookie.serialize('H_PS_PSSID', '1442_13290_21082_17001_20927'),
            cookie.serialize('PSINO', '5'),
            cookie.serialize('PSTM', '1518055990')
        ]
    }
}

let url = "http://www.baidu.com"

got.get(url,option).then(function(result){
    console.log(result.body)
})

再次执行脚本,将打印出来的结果放到html中可以看到不再原来的未登录的首页,而是已经跳转到登录界面,说明我们的cookie已经成功加载。 image.png

总结

通过got库,配合使用cookie 我们可以很方便的将cookie运用到我们的实际项目。

node兼职,远程办公

$
0
0

懂VUE +mongdb+node。该项目后期维护,适合练手 ,酬金按照完成代码变更数量计算,我的.wuyuliyu@163.com

新人求助,关于DataLoader

$
0
0

1.DataLoader 把数据库查询发出时,要求key 和 value 数目是一致的,但是有的时候,其中的子查询有可能查不出数据,整个查询返回的结果集的数量小于key的个数,这样导致DataLoader发生错误,而使整个查询结果都是null,请问有什么解决方法么

2 egg-graphql中有一个写法 .then(user => user.map(u => u.toJSON()))其中user已经是 Sequelize 查询后返回的结果了,已经是一个Promis 对象了,这样toJSON一下有什么特殊意义么?


高级售前工程师-坐标北京-APICloud

$
0
0

岗位职责 薪资15-20K

  1. 负责APICloud移动应用平台产品的售前技术支持工作,完成产品及系统平台的现场演示,编写投标类方案文件及标书的制作;
  2. 负责APICloud应用定制平台上APP定制项目的售前技术支持工作,根据需求对项目进行初步报价,编写技术服务方案等;
  3. 详细分析客户的业务需求,结合公司的技术产品,为客户提供最佳的解决方案,引导客户对技术和产品的选择;
  4. 通过对公司重点大客户业务需求的理解,不断深入挖掘大客户的潜在需求,快速设计和构造重点客户的解决方案; 任职资格:
  5. 本科以上学历,5年以上售前技术支持或开发经验,3年以上售前团队管理或技术管理经验。
  6. 了解APP和HTML5相关前端技术,熟悉移动App,Web网站,后端服务的开发流程。
  7. 熟悉至少一门后端语言,nodejs、php、python、java、C#等等。
  8. 熟悉企业后端业务系统,对移动互联网产品使用的开放服务有了解,有技术调研和分析的能力。
  9. 具有Android、iPhone、iPad等智能手机和平板上APP开发经验优先考虑;熟悉跨平台HybridApp开发者优先考虑。
  10. 有APICloud开发经验者优先。

工作地址 北京市海淀区龙翔路甲1号泰翔商务楼五层507、508室 联系人:王曼 15010775436

前端开发工程师-坐标北京-APICloud

$
0
0

工作职责 薪资:10-15K 1、参与公司系列产品web前端开发 2、根据产品需求,完成网页设计和页面制作; 3、实现UI和交互方面的需求,确保优质的用户体验效果 4、优化前端体验和响应速度,并保持良好兼容性 5、协助改进框架,提出产品进行结构、流程的优化建议

职位要求 1、本科以上学历,3年以上工作经验,了解必要的计算机网络协议 2、熟练掌握网站前端开发的相关技术 Javascript/CSS/HTML, 良好的前端代码实现 3、掌握至少一种JS(如ReactJS/Vue/Angular等)框架,掌握其原理,能独立开发常用组件 4、至少熟悉一种后端开发语言(PHP/Java/C/C++/python/nodejs等) 5、工作积极主动,能够承受工作压力。 6、对技术研究有极大热情,具备良好的沟通能力、学习能力、执行力 7、熟悉React者优先考虑 8、熟悉APICloud开发者优先考虑

工作地址 北京市海淀区龙翔路甲1号泰翔商务楼五层507、508室 联系人:王曼 15010775436

软件开发培训讲师-坐标北京-APICloud

$
0
0

岗位职责: 薪资10-15K

  1. 配合部门 Leader 完成培训课程教材的编制和完善;

  2. 配合公司 生态运营部 进行相关培训工作(如录播培训课程,直播培训课程及相关培训教程的编制或修订);

  3. 使用 APICloud 技术开发 教学使用的APP DEMO;

  4. 完成部门 Leader 下发的其他工作任务;

任职要求:

  1. 具备优秀的语音表达能力,能够将教学讲述内容清晰无误的传递给学员;

  2. 线下培训或线上直播课程时能够活跃课堂气氛,并和学员进行一定程度的互动沟通;

  3. 熟悉移动开发,熟练掌握 HTML、CSS、JavaScript 等前端开发技术,能够开发 移动端 APP(能够使用 APICloud 开发 APP 为最佳)

  4. 对技术充满热情,具备良好的团队合作意识和独立解决问题的能力,并能够承担一定的工作压力

  5. 原则上要求计算机相关专业,并2年以上工作经验,具备一下条件者,可放宽要求。

本岗位隶属公司APP开发培训部,主要招收具备培训讲师能力并兼备前端APP开发能力的复合人才。本岗位主要从事培训相关工作,如无意从事培训相关工作者,请勿投本岗位,本公司有其他相应的岗位供您选择。

工作地址 北京市海淀区龙翔路甲1号泰翔商务楼五层507、508室 联系人:王曼 15010775436

JAVA工程师-坐标青岛-APICloud

$
0
0

岗位职责: 薪资:6-10K 1.进行java和后台程序开发; 2.参与后台统计系统的研发; 3.后台网站系统研发。 任职要求: 1、 精通Java语言,有两年以上Java Web项目开发经验,有较强的面向对象设计能 力,掌握Structs、Spring、Hibernate框架; 2、 熟练使用Unix以及Linux的各种命令; 3、 熟练掌握mysql, mongodb, redis等数据库操作; 4、 有较强的自学能力和良好的语言表达能力,具备良好的团队协作精神; 5、 有较强的英语阅读能力,能独立查阅相关技术文档; 6、 有大型网站及服务开发经验者优先; 7、 有海量数据处理,统计数据分析经验者优先; 8、 有其他后端语言经验者优先,php、python、ruby、nodejs、C#等等; 9、 在github上有自己repo优先。

工作地址 山东省青岛市崂山区海尔路1号海尔信息产业园S座(通讯大楼)3楼公共大厅 联系人:刘进宇 18661817064

【求助】puppeteer输出页面pdf,报错:PrintToPDF is not implemented undefined

$
0
0

【求助】puppeteer输出页面pdf,报错:PrintToPDF is not implemented undefined

,额 这是怎么回事啊 求助

Node.js “我最在行” 小程序 自动爬库 + 自动答题 辅助脚本

$
0
0

github 地址,https://github.com/game-helper/weixin

欢迎 star 和 pr

我最在行

爬取题库、答题辅助

准备

  • Node.js 9.x 以上
  • MongoDB
  • 安装依赖 npm i

功能

抓请求之前,请完全删除小程序,重新搜索小程序名字进入。因为你之前登录过,后续抓不到登录请求了

爬取题库

爬题思路:不断进行好友对战获取题目,随意提交答案会返回正确答案,存入数据库,重复的忽略

分别使用两个微信号登录游戏,抓登录的请求 https://puzzle-gateway.zaih.com/pauthp/jwt

复制返回的 access_tokenaccount_id,填入 src/crawl.js

执行 npm run crawl开始自动爬取

如果出现带 leave单词的提示,说明上一局是异常退出的。只要关掉脚本,重新再运行就好了。

爬题需要一定的时间,也可以直接导入我爬好的题库 MongoShell BSON(.json)(5.5k 个题目,暂时还没爬全,后续更新) 数据库名为 wzzh

导入命令,注意你的文件路径

mongoimport -d wzzh -c quizzes --file ~/Downloads/questions.json --jsonArray --drop

答题辅助

用你要答题的号登录游戏,抓登录的请求 https://puzzle-gateway.zaih.com/pauthp/jwt

复制返回的 access_tokenaccount_id,填入 src/robot.js

再修改其中的 theme为你要答题的分类索引,比如 0 为全能王

执行 npm run robot开始智能答题,答题过程是全自动的

遇到题库里没有的题,程序会随机选一个答案提交,并将正确答案入库(所以尽量全的题库,才能保证胜率)

你只需要关注终端打印的信息即可,如果有报错,请提 issue 反馈给我们

截图

爬虫终端日志

数据库截图

擂台匹配日志

这是用一天的体力刷的

使用async如何进行并发处理?

$
0
0

<p>sequelize目前使用的是promise,多条update语句还是得用promise.all吗?</p>


基于vue + element-ui的管理平台模板更新啦

$
0
0

vue-element-admin-tpl

这是基于vue + element-ui开发的管理平台模板。 基于该模板,你可以快速搭建起管理平台页面,基础架构已经搭建好。 当然,只要有时间,组件我会不断丰富。

本次更新:

  • 增加了主题
  • 增加了响应式栅格布局
  • 响应式导航

已经安装依赖

  • vue
  • vuex
  • vue-router
  • axios
  • element-ui
  • nprogress
  • FontAwesome 4.7.0图标

实现组件

页面

截图

2018-02-08_231542.png

最后

欢迎使用,如果有更好的想法可以提个issue。

仓库地址预览地址

下面这段JS代码,什么语法检测工具可以发现错在哪里?

$
0
0
var asdfsdf = {
	sdfsdf: [
		['aaaaa', 'aaaaa'],
		['adsfsadf', 'wfwfwef'],
		['--sdf-','asdfasdf">asdfsadfsdf>'],
		['afds'],
		['asdf'],
		['sfdaf'],
		['adf',['adsf','sdf','asdf'], 'sdf:sdf']
		['-df--'],
		['sfd', 'dsf:sdf'],
	]
};

[‘adf’,[‘adsf’,‘sdf’,‘asdf’], ‘sdf:sdf’] 这句后门的逗号没写,但是jshint语法检测为何没有报错?

jshint检测通过 [JSHint: D:\workspace\test.js] ✓ 0 errors, [esc] to hide. [Finished in 0.3s]

fs.statSync 读取映射路径卡死

$
0
0

具体情况是:

  • 94服务器上的路径 /srv/test 是通过mount映射到93服务器上的/srv/test的用来存贮应用的附件
  • 但是当93服务器关机之后 fs.statSync('/srv/test/xxx.doc')读取映射路径就卡死了
  • 终端执行top查看 发现load average持续增高
  • 94上 cd /srv后执行 ls也是一直等待的状态,不显示/srv下的文件

请教各位大神 fs是否有timeout的机制? 或者更好的方法?

我觉得本站的帖子排序不合理

$
0
0

有些陈年旧贴有人回复了就会排到最前面,回复的内容可能只有发帖人才关心,对于其他人来说无关紧要,不应该占用版面让大家都看到。要排到前面也应该是有人点赞了帖子才对,点赞说明帖子内容有意义。

之前有写过个未完成的pornSpider,竟然还有三颗星,想问问大家如何规避风险?

$
0
0

最近手头上的事情没那么多,学习计划也在进行中。 之前push上去的pornSpider竟然还有三颗星,于是我想把这个东西完成了。 就是想问问大佬们,如果完成后开源了,有什么办法规避被请喝茶的风险?

Viewing all 14821 articles
Browse latest View live