[Express] Level 3: Massaging User Data

本文探讨了如何使用Express.js实现更灵活的路由处理方式,包括通过参数预处理提高代码灵活性,使用正则表达式验证输入格式,并介绍了如何处理动态路由中参数的有效性和格式验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Flexible Routes

Our current route only works when the city name argument matches exactly the properties in the cities object. This is a problem. We need a way to make our code more flexible.

Inside our route, call the parseCityName() function passing in the name parameter. Assign the return value to the new variable called cityName.

var cityName = parseCityName(request.params.name);

function parseCityName(name) {
  var parsedName = name[0].toUpperCase() + name.slice(1).toLowerCase();
  return parsedName;
}

Now, using the city name returned from the parseCityName() function, lookup the corresponding description using the cities object and store it in the correct variable that will make the rest of the function work as intended.

  var cityName = parseCityName(request.params.name);
  var cityInfo = cities[cityName];

 

var express = require('express');
var app = express();

var cities = {
  'Lotopia': 'Rough and mountainous',
  'Caspiana': 'Sky-top island',
  'Indigo': 'Vibrant and thriving',
  'Paradise': 'Lush, green plantation',
  'Flotilla': 'Bustling urban oasis'
};

app.get('/cities/:name', function (request, response) {
  var cityName = parseCityName(request.params.name);
  var cityInfo = cities[cityName];

  if(cityInfo) {
    response.json(cityInfo);
  } else {
    response.status(404).json('City not found');
  }
});

function parseCityName(name) {
  var parsedName = name[0].toUpperCase() + name.slice(1).toLowerCase();
  return parsedName;
}

app.listen(3000);                                                                                                                                                                                                                                                                                                                

 

Dynamic Routes I

Which Express function maps placeholders to callback functions, and is commonly used for running pre-conditions on Dynamic Routes?

Answer:

app.param();

 

Dynamic Routes II 

Whenever we use our name parameter we want to parse it a specific way. Let's clean up our existing code so that all routes with a name parameter get the same special handling.

Call app.param() to intercept requests that contain an argument called'name'. Remember app.param() takes a callback function as its second argument, which uses the same signature as a middleware.

var express = require('express');
var app = express();

app.param('name', function(request, response, next){

});

Inside the app.param() callback function, call the parseCityName() function with the submitted name parameter. Set the return value to a new property in the request object called cityName.

app.param('name', function(request, response, next){
    request.cityName = parseCityName(request.params.name);
});

Finally, call a function that moves processing to the next function in the stack.

app.param('name', function(request, response, next){
  request.cityName = parseCityName(request.params.name);
  next();
});

 

var express = require('express');
var app = express();

var cities = {
  'Lotopia': 'Rough and mountainous',
  'Caspiana': 'Sky-top island',
  'Indigo': 'Vibrant and thriving',
  'Paradise': 'Lush, green plantation',
  'Flotilla': 'Bustling urban oasis'
};

app.param('name', function(request, response, next){
    request.cityName = parseCityName(request.params.name);
  next();
});

app.get('/cities/:name', function (request, response) {
  var cityInfo = cities[request.cityName];
  if(cityInfo) {
    response.json(cityInfo);
  } else {
    response.status(404).json("City not found");
  }
});

function parseCityName(name){
  var parsedName = name[0].toUpperCase() + name.slice(1).toLowerCase();
  return parsedName;
}

app.listen(3000);                                                                                                                                                                                                                                                                                                            

 

Dynamic Routes III

The following code has a Dynamic Route that takes a year as an argument and returns the city created in that year. The problem with our current implementation is that it breaks when invalid data is sent on client requests. Let's add some basic validation.

Call a function that intercepts Dynamic Routes with the 'year' param.

app.param('year', function(request, response, next){

});

Inside of that function, use the isYearFormat() function to check whether the year parameter is in a valid format. If so, then move processing to the next function in the stack.

  if(isYearFormat(request.params.year)){
    next();
  }

If the year parameter is not in a valid format, then respond with a 400 HTTP status code and a JSON message 'Invalid Format for Year'.

app.param('year', function(request, response, next){
  if(isYearFormat(request.params.year)){
    next();
  }else{
      response.status(400).json('Invalid Format for Year');
  }
});

 

var express = require('express');
var app = express();

app.param('year', function(request, response, next){
  if(isYearFormat(request.params.year)){
    next();
  }else{
      response.status(400).json('Invalid Format for Year');
  }
});

var citiesYear = {
  5000: 'Lotopia',
  5100: 'Caspiana',
  5105: 'Indigo',
  6000: 'Paradise',
  7000: 'Flotilla'
};

function isYearFormat(value) {
  var regexp = RegExp(/^d{4}$/);
  return regexp.test(value);
}

app.get('/cities/year/:year', function(request, response) {
  var year = request.params.year;
  var city = citiesYear[year];

  if(!city) {
    response.status(404).json("No City found for given year");
  } else {
    response.json("In " + year + ", " + city + " is created.");
  }
});

app.listen(3000);                                                                                                                                                                                                                                                                                                       

 

Dynamic Routes IV

With the proper validations in place for the following code, what would the output be for a GET request to /cities/year/500?

Answer:

``` U8G2_SSD1306_128X64_NONAME_F_SW_I2C #include <U8g2lib.h> #include <Wire.h> #include "BluetoothSerial.h" BluetoothSerial BT; U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 22, 21, U8X8_PIN_NONE); int IN1 = 3; int IN2 = 5; #define CHINESE_FONT u8g2_font_wqy16_t_gb2312b // 完整中文字体 // 系统状态变量 enum SystemState { BOOTING, STANDBY, MASSAGING }; SystemState currentState = BOOTING; unsigned long bootStartTime = 0; void displayCenteredText(const char* text) { u8g2.clearBuffer(); int text_width = u8g2.getUTF8Width(text); u8g2.drawUTF8((128 - text_width)/2, 32, text); u8g2.sendBuffer(); } void setup() { // 初始化硬件 pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); // 初始化蓝牙 BT.begin("ESP32-Zh"); // 初始化OLED u8g2.begin(); u8g2.setFont(CHINESE_FONT); u8g2.setFontPosCenter(); // 显示开机画面 displayCenteredText("开机"); bootStartTime = millis(); } void loop() { // 状态机处理 switch(currentState){ case BOOTING: if(millis() - bootStartTime > 2000){ currentState = STANDBY; displayCenteredText("待机中"); } break; case STANDBY: case MASSAGING: // 蓝牙数据处理 if(BT.available()){ char data = BT.read(); switch(cmd){ case &#39;p&#39;: // 设置引脚编号(仅支持3或5) pinNum = Serial.parseInt(); if(pinNum != 3 && pinNum !=5){ Serial.println("Error: 仅支持3/5引脚"); return; } Serial.print("选中引脚"); // 中文提示 Serial.println(pinNum); break; case &#39;a&#39;: // 模拟输出(调速) ctrlVal = Serial.parseInt(); analogWrite(pinNum, ctrlVal); Serial.print("PWM值设置为"); Serial.println(ctrlVal); break; case &#39;d&#39;: // 数字输出 ctrlVal = Serial.parseInt(); digitalWrite(pinNum, ctrlVal); Serial.print("数字值设置为"); Serial.println(ctrlVal); break; default: Serial.println("未知指令"); break; } break; } }```请加上u8g2显示屏模块,实现在各种速度自动判断显示:高速运行中,低速运行中,待机中
04-03
``` U8G2_SSD1306_128X64_NONAME_F_SW_I2C #include <U8g2lib.h> #include <Wire.h> #include "BluetoothSerial.h" BluetoothSerial BT; U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, 22, 21, U8X8_PIN_NONE); // 引脚定义 int IN1 = 3; int IN2 = 5; #define CHINESE_FONT u8g2_font_wqy16_t_gb2312b #define HIGH_SPEED_THRESHOLD 150 // 高速阈值定义 // 系统状态变量 enum SystemState { BOOTING, STANDBY, MASSAGING }; SystemState currentState = BOOTING; unsigned long bootStartTime = 0; int currentSpeed = 0; // 当前速度值 int pinNum = 3; // 默认控制引脚 bool needUpdateDisplay = true; // 显示刷新标志 void displayCenteredText(const char* text) { u8g2.clearBuffer(); int text_width = u8g2.getUTF8Width(text); u8g2.drawUTF8((128 - text_width)/2, 32, text); u8g2.sendBuffer(); } void updateDisplayState() { if (currentSpeed == 0) { currentState = STANDBY; displayCenteredText("待机中"); } else if (currentSpeed >= HIGH_SPEED_THRESHOLD) { displayCenteredText("高速运行中"); } else { displayCenteredText("低速运行中"); } } void setup() { // 初始化硬件 pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); // 初始化蓝牙 BT.begin("ESP32-Zh"); // 初始化OLED u8g2.begin(); u8g2.setFont(CHINESE_FONT); u8g2.setFontPosCenter(); // 显示开机画面 displayCenteredText("开机"); bootStartTime = millis(); } void loop() { // 状态机处理 switch(currentState){ case BOOTING: if(millis() - bootStartTime > 2000){ currentState = STANDBY; displayCenteredText("待机中"); } break; case STANDBY: case MASSAGING: if(BT.available()){ String command = BT.readStringUntil(&#39;\n&#39;); command.trim(); if(command.length() > 0){ char cmd = command.charAt(0); String param = command.substring(1); int value = param.toInt(); switch(cmd){ case &#39;p&#39;: // 设置引脚 if(value != 3 && value !=5){ BT.println("Error: 仅支持3/5引脚"); break; } pinNum = value; BT.print("选中引脚"); BT.println(pinNum); break; case &#39;a&#39;: // 模拟输出 analogWrite(pinNum, value); currentSpeed = value; currentState = MASSAGING; updateDisplayState(); BT.print("PWM设置:"); BT.println(value); break; case &#39;d&#39;: // 数字输出 digitalWrite(pinNum, value); currentSpeed = value ? 255 : 0; currentState = value ? MASSAGING : STANDBY; updateDisplayState(); BT.print("数字设置:"); BT.println(value); break; default: BT.println("未知指令"); break; } } } break; } }```请增加pwm渐变功能和实现速度的多级调节,请用完整代码
04-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值